9 char *noname = "<none>";
10 char symname[] = SYMDEF;
12 char *thestring = "arm";
16 * -H1 -T0x10005000 -R4 is aif for risc os
17 * -H2 -T4128 -R4096 is plan9 format
18 * -H3 -T0xF0000020 -R4 is NetBSD format
19 * -H4 is IXP1200 (raw)
20 * -H5 -T0xC0008010 -R1024 is ipaq
21 * -H6 -R4096 no header with segments padded to pages
30 char buf1[5], buf2[SARMAG];
35 n = Bread(b, buf1, 5);
36 if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
37 v = 1; /* good enough for our purposes */
40 n = Bread(b, buf2, SARMAG);
41 v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
48 main(int argc, char *argv[])
53 Binit(&bso, 1, OWRITE);
68 if(c >= 0 && c < sizeof(debug))
82 INITTEXT = atolwhex(a);
87 INITDAT = atolwhex(a);
92 INITRND = atolwhex(a);
97 HEADTYPE = atolwhex(a);
98 /* do something about setting INITTEXT */
100 case 'x': /* produce export table */
102 if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
103 readundefs(ARGF(), SEXPORT);
105 case 'u': /* produce dynamically loadable module */
107 if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
108 readundefs(ARGF(), SIMPORT);
115 diag("usage: 5l [-options] objects");
118 if(!debug['9'] && !debug['U'] && !debug['B'])
130 diag("unknown -H option");
132 case 0: /* no header */
133 case 6: /* no header, padded segments */
142 case 1: /* aif for risc os */
145 INITTEXT = 0x10005000 + HEADR;
160 case 3: /* boot for NetBSD */
163 INITTEXT = 0xF0000020L;
169 case 4: /* boot for IXP1200 */
178 case 5: /* boot for ipaq */
181 INITTEXT = 0xC0008010;
187 case 7: /* elf executable */
188 HEADR = rnd(52L+3*32L, 16);
190 INITTEXT = 4096+HEADR;
197 if(INITDAT != 0 && INITRND != 0)
198 print("warning: -D0x%lux is ignored because of -R0x%lux\n",
201 Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
202 HEADTYPE, INITTEXT, INITDAT, INITRND);
207 zprg.from.name = D_NONE;
208 zprg.from.type = D_NONE;
209 zprg.from.reg = NREG;
219 cout = create(outfile, 1, 0775);
221 diag("%s: cannot create", outfile);
228 cbc = sizeof(buf.cbuf);
235 INITENTRY = "_mainp";
237 lookup(INITENTRY, 0)->type = SXREF;
239 lookup(INITENTRY, 0)->type = SXREF;
245 firstp = firstp->link;
249 EXPTAB = "_exporttab";
258 INITTEXT = INITDAT = 0;
283 Bprint(&bso, "%5.2f cpu time\n", cputime());
284 Bprint(&bso, "%ld memory used\n", thunk);
285 Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
286 Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
301 for(i=0; i<libraryp; i++) {
303 Bprint(&bso, "%5.2f autolib: %s\n", cputime(), library[i]);
307 for(h=0; h<nelem(hash); h++)
308 for(s = hash[h]; s != S; s = s->link)
328 long off, esym, cnt, l;
332 char name[100], pname[150];
334 char *e, *start, *stop;
336 if(file[0] == '-' && file[1] == 'l') {
338 snprint(name, sizeof name, "/%s/lib/lib%s.a", thestring, file+2);
340 snprint(name, sizeof name, "/usr/%clib/lib%s.a", thechar, file+2);
344 Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
348 diag("cannot open file: %s", file);
351 l = read(f, magbuf, SARMAG);
352 if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
353 /* load it as a regular file */
362 Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
363 l = read(f, &arhdr, SAR_HDR);
365 diag("%s: short read on archive file symbol header", file);
368 if(strncmp(arhdr.name, symname, strlen(symname))) {
369 diag("%s: first entry not symbol header", file);
373 esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
374 off = SARMAG + SAR_HDR;
377 * just bang the whole symbol file into memory
381 start = malloc(cnt + 10);
382 cnt = read(f, start, cnt);
393 Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
396 for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
400 snprint(pname, sizeof pname, "%s(%s)", file, s->name);
402 Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
405 l |= (e[2] & 0xff) << 8;
406 l |= (e[3] & 0xff) << 16;
407 l |= (e[4] & 0xff) << 24;
409 l = read(f, &arhdr, SAR_HDR);
412 if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
414 l = atolwhex(arhdr.size);
416 if(s->type == SXREF) {
417 diag("%s: failed to load: %s", file, s->name);
427 diag("%s: bad or out of date archive", file);
433 zaddr(uchar *p, Adr *a, Sym *h[])
441 if(c < 0 || c > NSYM){
442 print("sym out of range: %d\n", c);
452 if(a->reg < 0 || a->reg > NREG) {
453 print("register out of range %d\n", a->reg);
455 return 0; /* force real diagnostic */
460 print("unknown type %d\n", a->type);
462 return 0; /* force real diagnostic */
481 a->offset = p[4] | (p[5]<<8) |
482 (p[6]<<16) | (p[7]<<24);
487 while(nhunk < NSNAME)
489 a->sval = (char*)hunk;
493 memmove(a->sval, p+4, NSNAME);
498 while(nhunk < sizeof(Ieee))
500 a->ieee = (Ieee*)hunk;
504 a->ieee->l = p[4] | (p[5]<<8) |
505 (p[6]<<16) | (p[7]<<24);
506 a->ieee->h = p[8] | (p[9]<<8) |
507 (p[10]<<16) | (p[11]<<24);
515 if(i != D_AUTO && i != D_PARAM)
519 for(u=curauto; u; u=u->link)
527 while(nhunk < sizeof(Auto))
530 nhunk -= sizeof(Auto);
531 hunk += sizeof(Auto);
544 char name[1024], comp[256], *p;
550 if(histfrog[0]->name[1] == '/') {
554 if(histfrog[0]->name[1] == '.') {
555 snprint(name, sizeof name, ".");
559 snprint(name, sizeof name, "/%s/lib", thestring);
561 snprint(name, sizeof name, "/usr/%clib", thechar);
565 for(; i<histfrogp; i++) {
566 snprint(comp, sizeof comp, histfrog[i]->name+1);
568 p = strstr(comp, "$O");
571 memmove(p+1, p+2, strlen(p+2)+1);
575 p = strstr(comp, "$M");
578 if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
579 diag("library component too long");
582 memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
583 memmove(p, thestring, strlen(thestring));
585 if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
586 diag("library component too long");
592 for(i=0; i<libraryp; i++)
593 if(strcmp(name, library[i]) == 0)
595 if(libraryp == nelem(library)){
596 diag("too many autolibs; skipping %s", name);
600 p = malloc(strlen(name) + 1);
602 library[libraryp] = p;
603 p = malloc(strlen(obj) + 1);
605 libraryobj[libraryp] = p;
610 addhist(long line, int type)
616 u = malloc(sizeof(Auto));
617 s = malloc(sizeof(Sym));
618 s->name = malloc(2*(histfrogp+1) + 1);
627 for(i=0; i<histfrogp; i++) {
628 k = histfrog[i]->value;
653 * bad encoding of path components only allows
654 * MAXHIST components. if there is an overflow,
655 * first try to collapse xxx/..
657 for(i=1; i<histfrogp; i++)
658 if(strcmp(histfrog[i]->name+1, "..") == 0) {
659 memmove(histfrog+i-1, histfrog+i+1,
660 (histfrogp-i-1)*sizeof(histfrog[0]));
666 * next try to collapse .
668 for(i=0; i<histfrogp; i++)
669 if(strcmp(histfrog[i]->name+1, ".") == 0) {
670 memmove(histfrog+i, histfrog+i+1,
671 (histfrogp-i-1)*sizeof(histfrog[0]));
676 * last chance, just truncate from front
678 memmove(histfrog+0, histfrog+1,
679 (histfrogp-1)*sizeof(histfrog[0]));
682 histfrog[histfrogp-1] = s;
689 p->from.type = D_NONE;
694 readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
699 memmove(buf, good, stop - good);
704 n = read(f, stop, n);
711 ldobj(int f, long c, char *pn)
715 uchar *bloc, *bsize, *stop;
716 Sym *h[NSYM], *s, *di;
724 nfilen = malloc((files+16)*sizeof(char*));
725 memmove(nfilen, filen, files*sizeof(char*));
729 filen[files++] = strdup(pn);
736 memset(h, 0, sizeof(h));
746 if(r < 100 && r < c) { /* enough for largest prog */
747 bsize = readsome(f, buf.xbuf, bloc, bsize, c);
753 o = bloc[0]; /* as */
754 if(o <= AXXX || o >= ALAST) {
755 diag("%s: line %ld: opcode out of range %d", pn, pc-ipc, o);
756 print(" probably not a .5 file\n");
759 if(o == ANAME || o == ASIGNAME) {
762 sig = bloc[1] | (bloc[2]<<8) | (bloc[3]<<16) | (bloc[4]<<24);
766 stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
768 bsize = readsome(f, buf.xbuf, bloc, bsize, c);
772 stop = memchr(&bloc[3], 0, bsize-&bloc[3]);
774 fprint(2, "%s: name too long\n", pn);
778 v = bloc[1]; /* type */
779 o = bloc[2]; /* sym */
786 s = lookup((char*)bloc, r);
787 c -= &stop[1] - bloc;
791 if(s->sig != 0 && s->sig != sig)
792 diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
798 print(" ANAME %s\n", s->name);
800 if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
803 if(s->type != SFILE) {
808 if(histfrogp < MAXHIST) {
809 histfrog[histfrogp] = s;
817 if(nhunk < sizeof(Prog))
820 nhunk -= sizeof(Prog);
821 hunk += sizeof(Prog);
826 p->line = bloc[3] | (bloc[4]<<8) | (bloc[5]<<16) | (bloc[6]<<24);
828 r = zaddr(bloc+7, &p->from, h) + 7;
829 r += zaddr(bloc+r, &p->to, h);
834 diag("register out of range %d", p->reg);
844 if(p->to.offset == -1) {
849 addhist(p->line, D_FILE); /* 'z' */
851 addhist(p->to.offset, D_FILE1); /* 'Z' */
858 curtext->to.autom = curauto;
868 diag("GLOBL must have a name\n%P", p);
873 if(s->type == 0 || s->type == SXREF) {
877 if(s->type != SBSS) {
878 diag("redefinition: %s\n%P", s->name, p);
882 if(p->to.offset > s->value)
883 s->value = p->to.offset;
888 diag("DYNT without a sym\n%P", p);
893 if(di->type == SXREF) {
895 Bprint(&bso, "%P set to %d\n", p, dtype);
903 p->from.offset = di->value;
904 p->from.sym->type = SDATA;
906 diag("DYNT not in text: %P", p);
909 p->to.sym = curtext->from.sym;
910 p->to.type = D_CONST;
916 if(p->from.sym == S) {
917 diag("INIT without a sym\n%P", p);
921 diag("INIT without previous DYNT\n%P", p);
924 p->from.offset = di->value;
925 p->from.sym->type = SDATA;
931 if(p->from.sym == S) {
932 diag("DATA without a sym\n%P", p);
940 diag("unknown opcode\n%P", p);
948 curtext->to.autom = curauto;
953 autosize = (p->to.offset+3L) & ~3L;
954 p->to.offset = autosize;
958 diag("TEXT must have a name\n%P", p);
961 if(s->type != 0 && s->type != SXREF) {
966 diag("redefinition: %s\n%P", s->name, p);
984 if(p->from.type == D_CONST)
985 if(p->from.name == D_NONE)
986 if(p->from.offset < 0) {
987 p->from.offset = -p->from.offset;
993 if(p->from.type == D_CONST)
994 if(p->from.name == D_NONE)
995 if(p->from.offset < 0) {
996 p->from.offset = -p->from.offset;
1002 if(!vfp || p->from.type != D_FCONST)
1010 if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
1012 snprint(literal, sizeof literal, "$%lux", ieeedtof(p->from.ieee));
1013 s = lookup(literal, 0);
1020 t->from.type = D_OREG;
1022 t->from.name = D_EXTERN;
1028 p->from.type = D_OREG;
1030 p->from.name = D_EXTERN;
1039 if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
1040 /* size sb 18 max */
1041 snprint(literal, sizeof literal, "$%lux.%lux",
1042 p->from.ieee->l, p->from.ieee->h);
1043 s = lookup(literal, 0);
1050 t->from.type = D_OREG;
1052 t->from.name = D_EXTERN;
1058 p->from.type = D_OREG;
1060 p->from.name = D_EXTERN;
1070 if(p->to.type == D_BRANCH)
1071 p->to.offset += ipc;
1081 diag("truncated object file: %s", pn);
1085 lookup(char *symb, int v)
1093 for(p=symb; c = *p; p++)
1099 for(s = hash[h]; s != S; s = s->link)
1101 if(memcmp(s->name, symb, l) == 0)
1104 while(nhunk < sizeof(Sym))
1107 nhunk -= sizeof(Sym);
1108 hunk += sizeof(Sym);
1110 s->name = malloc(l);
1111 memmove(s->name, symb, l);
1128 while(nhunk < sizeof(Prog))
1131 nhunk -= sizeof(Prog);
1132 hunk += sizeof(Prog);
1145 if(thunk >= 5L*NHUNK) {
1147 if(thunk >= 25L*NHUNK)
1151 if(h == (char*)-1) {
1152 diag("out of memory");
1168 Bprint(&bso, "%5.2f profile 1\n", cputime());
1170 s = lookup("__mcount", 0);
1172 for(p = firstp->link; p != P; p = p->link) {
1173 if(p->as == ATEXT) {
1179 q->from.type = D_OREG;
1180 q->from.name = D_EXTERN;
1181 q->from.offset = n*4;
1185 q->to.type = D_CONST;
1194 p->from.type = D_OREG;
1195 p->from.name = D_EXTERN;
1197 p->from.offset = n*4 + 4;
1208 p->from.type = D_CONST;
1220 p->from.type = D_REG;
1221 p->from.reg = REGTMP;
1222 p->to.type = D_OREG;
1223 p->to.name = D_EXTERN;
1225 p->to.offset = n*4 + 4;
1237 q->from.type = D_OREG;
1238 q->from.name = D_EXTERN;
1241 q->to.type = D_CONST;
1248 static int brcond[] = {ABEQ, ABNE, ABCS, ABCC, ABMI, ABPL, ABVS, ABVC, ABHI, ABLS, ABGE, ABLT, ABGT, ABLE};
1254 Prog *p, *q, *q2, *ps2, *ps4;
1257 Bprint(&bso, "%5.2f profile 2\n", cputime());
1261 s2 = lookup("_tracein", 0);
1262 s4 = lookup("_traceout", 0);
1264 s2 = lookup("_profin", 0);
1265 s4 = lookup("_profout", 0);
1267 if(s2->type != STEXT || s4->type != STEXT) {
1269 diag("_tracein/_traceout not defined %d %d", s2->type, s4->type);
1271 diag("_profin/_profout not defined");
1277 for(p = firstp; p != P; p = p->link) {
1278 if(p->as == ATEXT) {
1279 if(p->from.sym == s2) {
1283 if(p->from.sym == s4) {
1289 for(p = firstp; p != P; p = p->link) {
1290 if(p->as == ATEXT) {
1291 if(p->reg & NOPROF) {
1310 if(debug['e']){ /* embedded tracing */
1319 q2->to.type = D_BRANCH;
1320 q2->to.sym = p->to.sym;
1326 p->to.type = D_BRANCH;
1336 if(debug['e']){ /* embedded tracing */
1357 if(p->scond != 14) {
1360 q->from = zprg.from;
1362 q->to.type = D_BRANCH;
1368 p->as = brcond[p->scond^1]; /* complement */
1370 p->from = zprg.from;
1372 p->to.type = D_BRANCH;
1373 p->cond = q->link->link; /* successor of RET */
1374 p->to.offset = q->link->link->pc;
1383 p->from = zprg.from;
1385 p->to.type = D_BRANCH;
1403 for(i=0; i<4; i++) {
1404 c = find1(0x04030201L, i+1);
1411 if(debug['d'] == 0){
1416 fnuxi8[i] = c+4; /* ms word first, then ls, even in little endian mode */
1421 Bprint(&bso, "inuxi = ");
1423 Bprint(&bso, "%d", inuxi1[i]);
1426 Bprint(&bso, "%d", inuxi2[i]);
1429 Bprint(&bso, "%d", inuxi4[i]);
1430 Bprint(&bso, "\nfnuxi = ");
1432 Bprint(&bso, "%d", fnuxi4[i]);
1435 Bprint(&bso, "%d", fnuxi8[i]);
1441 find1(long l, int c)
1454 ieeedtof(Ieee *ieeep)
1461 exp = (ieeep->h>>20) & ((1L<<11)-1L);
1462 exp -= (1L<<10) - 2L;
1463 v = (ieeep->h & 0xfffffL) << 3;
1464 v |= (ieeep->l >> 29) & 0x7L;
1465 if((ieeep->l >> 28) & 1) {
1468 v = (v & 0x7fffffL) >> 1;
1472 if(exp <= -126 || exp >= 130)
1473 diag("double fp to single fp overflow");
1474 v |= ((exp + 126) & 0xffL) << 23;
1475 v |= ieeep->h & 0x80000000L;
1480 ieeedtod(Ieee *ieeep)
1486 if(ieeep->h & (1L<<31)) {
1487 e.h = ieeep->h & ~(1L<<31);
1489 return -ieeedtod(&e);
1491 if(ieeep->l == 0 && ieeep->h == 0)
1493 fr = ieeep->l & ((1L<<16)-1L);
1495 fr += (ieeep->l>>16) & ((1L<<16)-1L);
1497 fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
1499 exp = (ieeep->h>>20) & ((1L<<11)-1L);
1500 exp -= (1L<<10) - 2L;
1501 return ldexp(fr, exp);
1511 diag("value != 0 on SXREF");
1513 diag("import index %d out of range", n);
1514 s->value = n<<Roffset;
1529 readundefs(char *f, int t)
1534 char *l, buf[256], *fields[64];
1538 b = Bopen(f, OREAD);
1540 diag("could not open %s: %r", f);
1543 while((l = Brdline(b, '\n')) != nil){
1545 if(n >= sizeof(buf)){
1546 diag("%s: line too long", f);
1551 n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
1552 if(n == nelem(fields)){
1553 diag("%s: bad format", f);
1556 for(i = 0; i < n; i++) {
1557 s = lookup(fields[i], 0);