174a4d8c2SCharles.Forsyth /*
274a4d8c2SCharles.Forsyth * obj.c
374a4d8c2SCharles.Forsyth * routines universal to all object files
474a4d8c2SCharles.Forsyth */
574a4d8c2SCharles.Forsyth #include <lib9.h>
645a20ab7Sforsyth #include <ctype.h>
774a4d8c2SCharles.Forsyth #include <bio.h>
8d67b7dadSforsyth #include <ar.h>
974a4d8c2SCharles.Forsyth #include "mach.h"
1074a4d8c2SCharles.Forsyth #include "obj.h"
1174a4d8c2SCharles.Forsyth
1274a4d8c2SCharles.Forsyth #define islocal(t) ((t)=='a' || (t)=='p')
1374a4d8c2SCharles.Forsyth
1474a4d8c2SCharles.Forsyth enum
1574a4d8c2SCharles.Forsyth {
1674a4d8c2SCharles.Forsyth NNAMES = 50,
1774a4d8c2SCharles.Forsyth MAXIS = 8, /* max length to determine if a file is a .? file */
1874a4d8c2SCharles.Forsyth MAXOFF = 0x7fffffff, /* larger than any possible local offset */
1974a4d8c2SCharles.Forsyth NHASH = 1024, /* must be power of two */
2074a4d8c2SCharles.Forsyth HASHMUL = 79L,
2174a4d8c2SCharles.Forsyth };
2274a4d8c2SCharles.Forsyth
2345a20ab7Sforsyth /* in [$OS].c */
2445a20ab7Sforsyth int _is5(char*),
2574a4d8c2SCharles.Forsyth _is6(char*),
2674a4d8c2SCharles.Forsyth _is8(char*),
2774a4d8c2SCharles.Forsyth _is9(char*),
2874a4d8c2SCharles.Forsyth _isk(char*),
2974a4d8c2SCharles.Forsyth _isq(char*),
3074a4d8c2SCharles.Forsyth _isv(char*),
31*2a571cc0SRichard Miller _isi(char*),
3274a4d8c2SCharles.Forsyth _read5(Biobuf*, Prog*),
3374a4d8c2SCharles.Forsyth _read6(Biobuf*, Prog*),
3474a4d8c2SCharles.Forsyth _read8(Biobuf*, Prog*),
3574a4d8c2SCharles.Forsyth _read9(Biobuf*, Prog*),
3674a4d8c2SCharles.Forsyth _readk(Biobuf*, Prog*),
3774a4d8c2SCharles.Forsyth _readq(Biobuf*, Prog*),
38*2a571cc0SRichard Miller _readv(Biobuf*, Prog*),
39*2a571cc0SRichard Miller _readi(Biobuf*, Prog*);
4074a4d8c2SCharles.Forsyth
4174a4d8c2SCharles.Forsyth typedef struct Obj Obj;
4274a4d8c2SCharles.Forsyth typedef struct Symtab Symtab;
4374a4d8c2SCharles.Forsyth
4474a4d8c2SCharles.Forsyth struct Obj /* functions to handle each intermediate (.$O) file */
4574a4d8c2SCharles.Forsyth {
4674a4d8c2SCharles.Forsyth char *name; /* name of each $O file */
4774a4d8c2SCharles.Forsyth int (*is)(char*); /* test for each type of $O file */
4874a4d8c2SCharles.Forsyth int (*read)(Biobuf*, Prog*); /* read for each type of $O file*/
4974a4d8c2SCharles.Forsyth };
5074a4d8c2SCharles.Forsyth
5174a4d8c2SCharles.Forsyth static Obj obj[] =
5274a4d8c2SCharles.Forsyth { /* functions to identify and parse each type of obj */
5345a20ab7Sforsyth /*[Obj68020]*/ {0, 0,},
54773d7fd2Sforsyth /*[ObjSparc]*/ "sparc .k", _isk, _readk,
55773d7fd2Sforsyth /*[ObjMips]*/ "mips .v", _isv, _readv,
56773d7fd2Sforsyth /*[Obj386]*/ "386 .8", _is8, _read8,
57773d7fd2Sforsyth /*[Obj960]*/ {0, 0,},
58773d7fd2Sforsyth /*[Obj3210]*/ {0, 0,},
59773d7fd2Sforsyth /*[ObjMips2]*/ {0, 0,},
60773d7fd2Sforsyth /*[Obj29000]*/ {0, 0,},
61773d7fd2Sforsyth /*[ObjArm]*/ "arm .5", _is5, _read5,
62773d7fd2Sforsyth /*[ObjPower]*/ "power .q", _isq, _readq,
63773d7fd2Sforsyth /*[ObjMips2le]*/ {0, 0,},
64773d7fd2Sforsyth /*[ObjAlpha]*/ {0, 0,},
65773d7fd2Sforsyth /*[ObjSparc64]*/ {0, 0,},
66773d7fd2Sforsyth /*[ObjAmd64]*/ "amd64 .6", _is6, _read6,
67773d7fd2Sforsyth /*[ObjSpim]*/ {0, 0,},
68773d7fd2Sforsyth /*[ObjPower64]*/ "power64 .9", _is9, _read9,
69*2a571cc0SRichard Miller /*[ObjRiscv]*/ "riscv .i", _isi, _readi,
70*2a571cc0SRichard Miller /*[ObjRiscv64]*/ "riscv64 .j", _isi, _readi,
71773d7fd2Sforsyth /*[Maxobjtype]*/ 0, 0
7274a4d8c2SCharles.Forsyth };
7374a4d8c2SCharles.Forsyth
7474a4d8c2SCharles.Forsyth struct Symtab
7574a4d8c2SCharles.Forsyth {
7674a4d8c2SCharles.Forsyth struct Sym s;
7774a4d8c2SCharles.Forsyth struct Symtab *next;
7874a4d8c2SCharles.Forsyth };
7974a4d8c2SCharles.Forsyth
8074a4d8c2SCharles.Forsyth static Symtab *hash[NHASH];
8174a4d8c2SCharles.Forsyth static Sym *names[NNAMES]; /* working set of active names */
8274a4d8c2SCharles.Forsyth
8374a4d8c2SCharles.Forsyth static int processprog(Prog*,int); /* decode each symbol reference */
8474a4d8c2SCharles.Forsyth static void objreset(void);
85d67b7dadSforsyth static void objlookup(int, char *, int, uint);
8674a4d8c2SCharles.Forsyth static void objupdate(int, int);
8774a4d8c2SCharles.Forsyth
8874a4d8c2SCharles.Forsyth int
objtype(Biobuf * bp,char ** name)8974a4d8c2SCharles.Forsyth objtype(Biobuf *bp, char **name)
9074a4d8c2SCharles.Forsyth {
9174a4d8c2SCharles.Forsyth int i;
9274a4d8c2SCharles.Forsyth char buf[MAXIS];
9374a4d8c2SCharles.Forsyth
9474a4d8c2SCharles.Forsyth if(Bread(bp, buf, MAXIS) < MAXIS)
9574a4d8c2SCharles.Forsyth return -1;
9674a4d8c2SCharles.Forsyth Bseek(bp, -MAXIS, 1);
9774a4d8c2SCharles.Forsyth for (i = 0; i < Maxobjtype; i++) {
9874a4d8c2SCharles.Forsyth if (obj[i].is && (*obj[i].is)(buf)) {
9974a4d8c2SCharles.Forsyth if (name)
10074a4d8c2SCharles.Forsyth *name = obj[i].name;
10174a4d8c2SCharles.Forsyth return i;
10274a4d8c2SCharles.Forsyth }
10374a4d8c2SCharles.Forsyth }
10474a4d8c2SCharles.Forsyth return -1;
10574a4d8c2SCharles.Forsyth }
10674a4d8c2SCharles.Forsyth
10774a4d8c2SCharles.Forsyth int
isar(Biobuf * bp)10874a4d8c2SCharles.Forsyth isar(Biobuf *bp)
10974a4d8c2SCharles.Forsyth {
11074a4d8c2SCharles.Forsyth int n;
11174a4d8c2SCharles.Forsyth char magbuf[SARMAG];
11274a4d8c2SCharles.Forsyth
11374a4d8c2SCharles.Forsyth n = Bread(bp, magbuf, SARMAG);
11474a4d8c2SCharles.Forsyth if(n == SARMAG && strncmp(magbuf, ARMAG, SARMAG) == 0)
11574a4d8c2SCharles.Forsyth return 1;
11674a4d8c2SCharles.Forsyth return 0;
11774a4d8c2SCharles.Forsyth }
11874a4d8c2SCharles.Forsyth
11974a4d8c2SCharles.Forsyth /*
12074a4d8c2SCharles.Forsyth * determine what kind of object file this is and process it.
12174a4d8c2SCharles.Forsyth * return whether or not this was a recognized intermediate file.
12274a4d8c2SCharles.Forsyth */
12374a4d8c2SCharles.Forsyth int
readobj(Biobuf * bp,int objtype)12474a4d8c2SCharles.Forsyth readobj(Biobuf *bp, int objtype)
12574a4d8c2SCharles.Forsyth {
12674a4d8c2SCharles.Forsyth Prog p;
12774a4d8c2SCharles.Forsyth
12874a4d8c2SCharles.Forsyth if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
12974a4d8c2SCharles.Forsyth return 1;
13074a4d8c2SCharles.Forsyth objreset();
13174a4d8c2SCharles.Forsyth while ((*obj[objtype].read)(bp, &p))
13274a4d8c2SCharles.Forsyth if (!processprog(&p, 1))
13374a4d8c2SCharles.Forsyth return 0;
13474a4d8c2SCharles.Forsyth return 1;
13574a4d8c2SCharles.Forsyth }
13674a4d8c2SCharles.Forsyth
13774a4d8c2SCharles.Forsyth int
readar(Biobuf * bp,int objtype,vlong end,int doautos)138d67b7dadSforsyth readar(Biobuf *bp, int objtype, vlong end, int doautos)
13974a4d8c2SCharles.Forsyth {
14074a4d8c2SCharles.Forsyth Prog p;
14174a4d8c2SCharles.Forsyth
14274a4d8c2SCharles.Forsyth if (objtype < 0 || objtype >= Maxobjtype || obj[objtype].is == 0)
14374a4d8c2SCharles.Forsyth return 1;
14474a4d8c2SCharles.Forsyth objreset();
145d67b7dadSforsyth while ((*obj[objtype].read)(bp, &p) && Boffset(bp) < end)
14674a4d8c2SCharles.Forsyth if (!processprog(&p, doautos))
14774a4d8c2SCharles.Forsyth return 0;
14874a4d8c2SCharles.Forsyth return 1;
14974a4d8c2SCharles.Forsyth }
15074a4d8c2SCharles.Forsyth
15174a4d8c2SCharles.Forsyth /*
15274a4d8c2SCharles.Forsyth * decode a symbol reference or definition
15374a4d8c2SCharles.Forsyth */
15474a4d8c2SCharles.Forsyth static int
processprog(Prog * p,int doautos)15574a4d8c2SCharles.Forsyth processprog(Prog *p, int doautos)
15674a4d8c2SCharles.Forsyth {
15774a4d8c2SCharles.Forsyth if(p->kind == aNone)
15874a4d8c2SCharles.Forsyth return 1;
15974a4d8c2SCharles.Forsyth if(p->sym < 0 || p->sym >= NNAMES)
16074a4d8c2SCharles.Forsyth return 0;
16174a4d8c2SCharles.Forsyth switch(p->kind)
16274a4d8c2SCharles.Forsyth {
16374a4d8c2SCharles.Forsyth case aName:
16474a4d8c2SCharles.Forsyth if (!doautos)
16574a4d8c2SCharles.Forsyth if(p->type != 'U' && p->type != 'b')
16674a4d8c2SCharles.Forsyth break;
167d67b7dadSforsyth objlookup(p->sym, p->id, p->type, p->sig);
16874a4d8c2SCharles.Forsyth break;
16974a4d8c2SCharles.Forsyth case aText:
17074a4d8c2SCharles.Forsyth objupdate(p->sym, 'T');
17174a4d8c2SCharles.Forsyth break;
17274a4d8c2SCharles.Forsyth case aData:
17374a4d8c2SCharles.Forsyth objupdate(p->sym, 'D');
17474a4d8c2SCharles.Forsyth break;
17574a4d8c2SCharles.Forsyth default:
17674a4d8c2SCharles.Forsyth break;
17774a4d8c2SCharles.Forsyth }
17874a4d8c2SCharles.Forsyth return 1;
17974a4d8c2SCharles.Forsyth }
18074a4d8c2SCharles.Forsyth
18174a4d8c2SCharles.Forsyth /*
18274a4d8c2SCharles.Forsyth * find the entry for s in the symbol array.
18374a4d8c2SCharles.Forsyth * make a new entry if it is not already there.
18474a4d8c2SCharles.Forsyth */
18574a4d8c2SCharles.Forsyth static void
objlookup(int id,char * name,int type,uint sig)186d67b7dadSforsyth objlookup(int id, char *name, int type, uint sig)
18774a4d8c2SCharles.Forsyth {
18874a4d8c2SCharles.Forsyth long h;
18974a4d8c2SCharles.Forsyth char *cp;
19074a4d8c2SCharles.Forsyth Sym *s;
19174a4d8c2SCharles.Forsyth Symtab *sp;
19274a4d8c2SCharles.Forsyth
19374a4d8c2SCharles.Forsyth s = names[id];
19474a4d8c2SCharles.Forsyth if(s && strcmp(s->name, name) == 0) {
19574a4d8c2SCharles.Forsyth s->type = type;
196d67b7dadSforsyth s->sig = sig;
19774a4d8c2SCharles.Forsyth return;
19874a4d8c2SCharles.Forsyth }
19974a4d8c2SCharles.Forsyth
20074a4d8c2SCharles.Forsyth h = *name;
20174a4d8c2SCharles.Forsyth for(cp = name+1; *cp; h += *cp++)
20274a4d8c2SCharles.Forsyth h *= HASHMUL;
20374a4d8c2SCharles.Forsyth if(h < 0)
20474a4d8c2SCharles.Forsyth h = ~h;
20574a4d8c2SCharles.Forsyth h &= (NHASH-1);
20674a4d8c2SCharles.Forsyth if (type == 'U' || type == 'b' || islocal(type)) {
20774a4d8c2SCharles.Forsyth for(sp = hash[h]; sp; sp = sp->next)
20874a4d8c2SCharles.Forsyth if(strcmp(sp->s.name, name) == 0) {
20974a4d8c2SCharles.Forsyth switch(sp->s.type) {
21074a4d8c2SCharles.Forsyth case 'T':
21174a4d8c2SCharles.Forsyth case 'D':
21274a4d8c2SCharles.Forsyth case 'U':
21374a4d8c2SCharles.Forsyth if (type == 'U') {
21474a4d8c2SCharles.Forsyth names[id] = &sp->s;
21574a4d8c2SCharles.Forsyth return;
21674a4d8c2SCharles.Forsyth }
21774a4d8c2SCharles.Forsyth break;
21874a4d8c2SCharles.Forsyth case 't':
21974a4d8c2SCharles.Forsyth case 'd':
22074a4d8c2SCharles.Forsyth case 'b':
22174a4d8c2SCharles.Forsyth if (type == 'b') {
22274a4d8c2SCharles.Forsyth names[id] = &sp->s;
22374a4d8c2SCharles.Forsyth return;
22474a4d8c2SCharles.Forsyth }
22574a4d8c2SCharles.Forsyth break;
22674a4d8c2SCharles.Forsyth case 'a':
22774a4d8c2SCharles.Forsyth case 'p':
22874a4d8c2SCharles.Forsyth if (islocal(type)) {
22974a4d8c2SCharles.Forsyth names[id] = &sp->s;
23074a4d8c2SCharles.Forsyth return;
23174a4d8c2SCharles.Forsyth }
23274a4d8c2SCharles.Forsyth break;
23374a4d8c2SCharles.Forsyth default:
23474a4d8c2SCharles.Forsyth break;
23574a4d8c2SCharles.Forsyth }
23674a4d8c2SCharles.Forsyth }
23774a4d8c2SCharles.Forsyth }
23874a4d8c2SCharles.Forsyth sp = malloc(sizeof(Symtab));
23974a4d8c2SCharles.Forsyth sp->s.name = name;
24074a4d8c2SCharles.Forsyth sp->s.type = type;
241d67b7dadSforsyth sp->s.sig = sig;
24274a4d8c2SCharles.Forsyth sp->s.value = islocal(type) ? MAXOFF : 0;
24374a4d8c2SCharles.Forsyth names[id] = &sp->s;
24474a4d8c2SCharles.Forsyth sp->next = hash[h];
24574a4d8c2SCharles.Forsyth hash[h] = sp;
24674a4d8c2SCharles.Forsyth return;
24774a4d8c2SCharles.Forsyth }
24874a4d8c2SCharles.Forsyth /*
24974a4d8c2SCharles.Forsyth * traverse the symbol lists
25074a4d8c2SCharles.Forsyth */
25174a4d8c2SCharles.Forsyth void
objtraverse(void (* fn)(Sym *,void *),void * pointer)25274a4d8c2SCharles.Forsyth objtraverse(void (*fn)(Sym*, void*), void *pointer)
25374a4d8c2SCharles.Forsyth {
25474a4d8c2SCharles.Forsyth int i;
25574a4d8c2SCharles.Forsyth Symtab *s;
25674a4d8c2SCharles.Forsyth
25774a4d8c2SCharles.Forsyth for(i = 0; i < NHASH; i++)
25874a4d8c2SCharles.Forsyth for(s = hash[i]; s; s = s->next)
25974a4d8c2SCharles.Forsyth (*fn)(&s->s, pointer);
26074a4d8c2SCharles.Forsyth }
26174a4d8c2SCharles.Forsyth
26274a4d8c2SCharles.Forsyth /*
26374a4d8c2SCharles.Forsyth * update the offset information for a 'a' or 'p' symbol in an intermediate file
26474a4d8c2SCharles.Forsyth */
26574a4d8c2SCharles.Forsyth void
_offset(int id,vlong off)266d67b7dadSforsyth _offset(int id, vlong off)
26774a4d8c2SCharles.Forsyth {
26874a4d8c2SCharles.Forsyth Sym *s;
26974a4d8c2SCharles.Forsyth
27074a4d8c2SCharles.Forsyth s = names[id];
27174a4d8c2SCharles.Forsyth if (s && s->name[0] && islocal(s->type) && s->value > off)
27274a4d8c2SCharles.Forsyth s->value = off;
27374a4d8c2SCharles.Forsyth }
27474a4d8c2SCharles.Forsyth
27574a4d8c2SCharles.Forsyth /*
27674a4d8c2SCharles.Forsyth * update the type of a global text or data symbol
27774a4d8c2SCharles.Forsyth */
27874a4d8c2SCharles.Forsyth static void
objupdate(int id,int type)27974a4d8c2SCharles.Forsyth objupdate(int id, int type)
28074a4d8c2SCharles.Forsyth {
28174a4d8c2SCharles.Forsyth Sym *s;
28274a4d8c2SCharles.Forsyth
28374a4d8c2SCharles.Forsyth s = names[id];
28474a4d8c2SCharles.Forsyth if (s && s->name[0])
28574a4d8c2SCharles.Forsyth if (s->type == 'U')
28674a4d8c2SCharles.Forsyth s->type = type;
28774a4d8c2SCharles.Forsyth else if (s->type == 'b')
28874a4d8c2SCharles.Forsyth s->type = tolower(type);
28974a4d8c2SCharles.Forsyth }
29074a4d8c2SCharles.Forsyth
29174a4d8c2SCharles.Forsyth /*
29274a4d8c2SCharles.Forsyth * look for the next file in an archive
29374a4d8c2SCharles.Forsyth */
29474a4d8c2SCharles.Forsyth int
nextar(Biobuf * bp,int offset,char * buf)29574a4d8c2SCharles.Forsyth nextar(Biobuf *bp, int offset, char *buf)
29674a4d8c2SCharles.Forsyth {
29774a4d8c2SCharles.Forsyth struct ar_hdr a;
29874a4d8c2SCharles.Forsyth int i, r;
29974a4d8c2SCharles.Forsyth long arsize;
30074a4d8c2SCharles.Forsyth
30174a4d8c2SCharles.Forsyth if (offset&01)
30274a4d8c2SCharles.Forsyth offset++;
30374a4d8c2SCharles.Forsyth Bseek(bp, offset, 0);
30474a4d8c2SCharles.Forsyth r = Bread(bp, &a, SAR_HDR);
30574a4d8c2SCharles.Forsyth if(r != SAR_HDR)
30674a4d8c2SCharles.Forsyth return 0;
30774a4d8c2SCharles.Forsyth if(strncmp(a.fmag, ARFMAG, sizeof(a.fmag)))
30874a4d8c2SCharles.Forsyth return -1;
30974a4d8c2SCharles.Forsyth for(i=0; i<sizeof(a.name) && i<SARNAME && a.name[i] != ' '; i++)
31074a4d8c2SCharles.Forsyth buf[i] = a.name[i];
31174a4d8c2SCharles.Forsyth buf[i] = 0;
312d67b7dadSforsyth arsize = strtol(a.size, 0, 0);
31374a4d8c2SCharles.Forsyth if (arsize&1)
31474a4d8c2SCharles.Forsyth arsize++;
31574a4d8c2SCharles.Forsyth return arsize + SAR_HDR;
31674a4d8c2SCharles.Forsyth }
31774a4d8c2SCharles.Forsyth
31874a4d8c2SCharles.Forsyth static void
objreset(void)31974a4d8c2SCharles.Forsyth objreset(void)
32074a4d8c2SCharles.Forsyth {
32174a4d8c2SCharles.Forsyth int i;
32274a4d8c2SCharles.Forsyth Symtab *s, *n;
32374a4d8c2SCharles.Forsyth
32474a4d8c2SCharles.Forsyth for(i = 0; i < NHASH; i++) {
32574a4d8c2SCharles.Forsyth for(s = hash[i]; s; s = n) {
32674a4d8c2SCharles.Forsyth n = s->next;
32774a4d8c2SCharles.Forsyth free(s->s.name);
32874a4d8c2SCharles.Forsyth free(s);
32974a4d8c2SCharles.Forsyth }
33074a4d8c2SCharles.Forsyth hash[i] = 0;
33174a4d8c2SCharles.Forsyth }
33274a4d8c2SCharles.Forsyth memset(names, 0, sizeof names);
33374a4d8c2SCharles.Forsyth }
334