1 // Inferno utils/6l/obj.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
3 //
4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 // Portions Copyright © 1997-1999 Vita Nuova Limited
7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 // Portions Copyright © 2004,2006 Bruce Ellis
9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 // Portions Copyright © 2009 The Go Authors. All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 // Reading object files.
32
33 #define EXTERN
34 #include "l.h"
35 #include "../ld/lib.h"
36 #include "../ld/elf.h"
37 #include "../ld/macho.h"
38 #include "../ld/dwarf.h"
39 #include "../ld/pe.h"
40 #include <ar.h>
41
42 char *noname = "<none>";
43 char* thestring = "amd64";
44 char* paramspace = "FP";
45
46 Header headers[] = {
47 "plan9x32", Hplan9x32,
48 "plan9", Hplan9x64,
49 "elf", Helf,
50 "darwin", Hdarwin,
51 "linux", Hlinux,
52 "freebsd", Hfreebsd,
53 "openbsd", Hopenbsd,
54 "windows", Hwindows,
55 "windowsgui", Hwindows,
56 0, 0
57 };
58
59 /*
60 * -Hplan9x32 -T4136 -R4096 is plan9 64-bit format
61 * -Hplan9 -T4128 -R4096 is plan9 32-bit format
62 * -Helf -T0x80110000 -R4096 is ELF32
63 * -Hdarwin -Tx -Rx is apple MH-exec
64 * -Hlinux -Tx -Rx is linux elf-exec
65 * -Hfreebsd -Tx -Rx is FreeBSD elf-exec
66 * -Hopenbsd -Tx -Rx is OpenBSD elf-exec
67 * -Hwindows -Tx -Rx is MS Windows PE32+
68 *
69 * options used: 189BLQSWabcjlnpsvz
70 */
71
72 void
73 usage(void)
74 {
75 fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n");
76 exits("usage");
77 }
78
79 void
80 main(int argc, char *argv[])
81 {
82 int c;
83
84 Binit(&bso, 1, OWRITE);
85 listinit();
86 memset(debug, 0, sizeof(debug));
87 nerrors = 0;
88 outfile = nil;
89 HEADTYPE = -1;
90 INITTEXT = -1;
91 INITDAT = -1;
92 INITRND = -1;
93 INITENTRY = 0;
94
95 ARGBEGIN {
96 default:
97 c = ARGC();
98 if(c == 'l')
99 usage();
100 if(c >= 0 && c < sizeof(debug))
101 debug[c]++;
102 break;
103 case 'o': /* output to (next arg) */
104 outfile = EARGF(usage());
105 break;
106 case 'E':
107 INITENTRY = EARGF(usage());
108 break;
109 case 'H':
110 HEADTYPE = headtype(EARGF(usage()));
111 break;
112 case 'I':
113 interpreter = EARGF(usage());
114 break;
115 case 'L':
116 Lflag(EARGF(usage()));
117 break;
118 case 'T':
119 INITTEXT = atolwhex(EARGF(usage()));
120 break;
121 case 'D':
122 INITDAT = atolwhex(EARGF(usage()));
123 break;
124 case 'R':
125 INITRND = atolwhex(EARGF(usage()));
126 break;
127 case 'r':
128 rpath = EARGF(usage());
129 break;
130 case 'V':
131 print("%cl version %s\n", thechar, getgoversion());
132 errorexit();
133 } ARGEND
134
135 if(argc != 1)
136 usage();
137
138 mywhatsys(); // get goos
139
140 if(HEADTYPE == -1)
141 HEADTYPE = headtype(goos);
142
143 if(outfile == nil) {
144 if(HEADTYPE == Hwindows)
145 outfile = "6.out.exe";
146 else
147 outfile = "6.out";
148 }
149
150 libinit();
151
152 switch(HEADTYPE) {
153 default:
154 diag("unknown -H option");
155 errorexit();
156 case Hplan9x32: /* plan 9 */
157 HEADR = 32L+8L;
158 if(INITTEXT == -1)
159 INITTEXT = 4096+HEADR;
160 if(INITDAT == -1)
161 INITDAT = 0;
162 if(INITRND == -1)
163 INITRND = 4096;
164 break;
165 case Hplan9x64: /* plan 9 */
166 HEADR = 32L;
167 if(INITTEXT == -1)
168 INITTEXT = 4096+32;
169 if(INITDAT == -1)
170 INITDAT = 0;
171 if(INITRND == -1)
172 INITRND = 4096;
173 break;
174 case Helf: /* elf32 executable */
175 HEADR = rnd(52L+3*32L, 16);
176 if(INITTEXT == -1)
177 INITTEXT = 0x80110000L;
178 if(INITDAT == -1)
179 INITDAT = 0;
180 if(INITRND == -1)
181 INITRND = 4096;
182 break;
183 case Hdarwin: /* apple MACH */
184 /*
185 * OS X system constant - offset from 0(GS) to our TLS.
186 * Explained in ../../libcgo/darwin_amd64.c.
187 */
188 tlsoffset = 0x8a0;
189 machoinit();
190 HEADR = INITIAL_MACHO_HEADR;
191 if(INITRND == -1)
192 INITRND = 4096;
193 if(INITTEXT == -1)
194 INITTEXT = 4096+HEADR;
195 if(INITDAT == -1)
196 INITDAT = 0;
197 break;
198 case Hlinux: /* elf64 executable */
199 case Hfreebsd: /* freebsd */
200 case Hopenbsd: /* openbsd */
201 /*
202 * ELF uses TLS offset negative from FS.
203 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
204 * Also known to ../../pkg/runtime/linux/amd64/sys.s
205 * and ../../libcgo/linux_amd64.s.
206 */
207 tlsoffset = -16;
208 elfinit();
209 HEADR = ELFRESERVE;
210 if(INITTEXT == -1)
211 INITTEXT = (1<<22)+HEADR;
212 if(INITDAT == -1)
213 INITDAT = 0;
214 if(INITRND == -1)
215 INITRND = 4096;
216 break;
217 case Hwindows: /* PE executable */
218 peinit();
219 HEADR = PEFILEHEADR;
220 if(INITTEXT == -1)
221 INITTEXT = PEBASE+PESECTHEADR;
222 if(INITDAT == -1)
223 INITDAT = 0;
224 if(INITRND == -1)
225 INITRND = PESECTALIGN;
226 break;
227 }
228 if(INITDAT != 0 && INITRND != 0)
229 print("warning: -D0x%llux is ignored because of -R0x%ux\n",
230 INITDAT, INITRND);
231 if(debug['v'])
232 Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
233 HEADTYPE, INITTEXT, INITDAT, INITRND);
234 Bflush(&bso);
235 instinit();
236
237 zprg.link = P;
238 zprg.pcond = P;
239 zprg.back = 2;
240 zprg.as = AGOK;
241 zprg.from.type = D_NONE;
242 zprg.from.index = D_NONE;
243 zprg.from.scale = 1;
244 zprg.to = zprg.from;
245 zprg.mode = 64;
246
247 pcstr = "%.6llux ";
248 nuxiinit();
249 histgen = 0;
250 pc = 0;
251 dtype = 4;
252 version = 0;
253 cbp = buf.cbuf;
254 cbc = sizeof(buf.cbuf);
255
256 addlibpath("command line", "command line", argv[0], "main");
257 loadlib();
258 deadcode();
259 patch();
260 follow();
261 doelf();
262 if(HEADTYPE == Hdarwin)
263 domacho();
264 dostkoff();
265 dostkcheck();
266 paramspace = "SP"; /* (FP) now (SP) on output */
267 if(debug['p'])
268 if(debug['1'])
269 doprof1();
270 else
271 doprof2();
272 span();
273 if(HEADTYPE == Hwindows)
274 dope();
275 addexport();
276 textaddress();
277 pclntab();
278 symtab();
279 dodata();
280 address();
281 doweak();
282 reloc();
283 asmb();
284 undef();
285 if(debug['v']) {
286 Bprint(&bso, "%5.2f cpu time\n", cputime());
287 Bprint(&bso, "%d symbols\n", nsymbol);
288 Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
289 Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
290 }
291 Bflush(&bso);
292
293 errorexit();
294 }
295
296 static Sym*
297 zsym(char *pn, Biobuf *f, Sym *h[])
298 {
299 int o;
300
301 o = BGETC(f);
302 if(o < 0 || o >= NSYM || h[o] == nil)
303 mangle(pn);
304 return h[o];
305 }
306
307 static void
308 zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
309 {
310 int t;
311 int32 l;
312 Sym *s;
313 Auto *u;
314
315 t = BGETC(f);
316 a->index = D_NONE;
317 a->scale = 0;
318 if(t & T_INDEX) {
319 a->index = BGETC(f);
320 a->scale = BGETC(f);
321 }
322 a->offset = 0;
323 if(t & T_OFFSET) {
324 a->offset = Bget4(f);
325 if(t & T_64) {
326 a->offset &= 0xFFFFFFFFULL;
327 a->offset |= (vlong)Bget4(f) << 32;
328 }
329 }
330 a->sym = S;
331 if(t & T_SYM)
332 a->sym = zsym(pn, f, h);
333 a->type = D_NONE;
334 if(t & T_FCONST) {
335 a->ieee.l = Bget4(f);
336 a->ieee.h = Bget4(f);
337 a->type = D_FCONST;
338 } else
339 if(t & T_SCONST) {
340 Bread(f, a->scon, NSNAME);
341 a->type = D_SCONST;
342 }
343 if(t & T_TYPE)
344 a->type = BGETC(f);
345 if(a->type < 0 || a->type >= D_SIZE)
346 mangle(pn);
347 adrgotype = S;
348 if(t & T_GOTYPE)
349 adrgotype = zsym(pn, f, h);
350 s = a->sym;
351 t = a->type;
352 if(t == D_INDIR+D_GS)
353 a->offset += tlsoffset;
354 if(t != D_AUTO && t != D_PARAM) {
355 if(s && adrgotype)
356 s->gotype = adrgotype;
357 return;
358 }
359 l = a->offset;
360 for(u=curauto; u; u=u->link) {
361 if(u->asym == s)
362 if(u->type == t) {
363 if(u->aoffset > l)
364 u->aoffset = l;
365 if(adrgotype)
366 u->gotype = adrgotype;
367 return;
368 }
369 }
370
371 switch(t) {
372 case D_FILE:
373 case D_FILE1:
374 case D_AUTO:
375 case D_PARAM:
376 if(s == S)
377 mangle(pn);
378 }
379
380 u = mal(sizeof(*u));
381 u->link = curauto;
382 curauto = u;
383 u->asym = s;
384 u->aoffset = l;
385 u->type = t;
386 u->gotype = adrgotype;
387 }
388
389 void
390 nopout(Prog *p)
391 {
392 p->as = ANOP;
393 p->from.type = D_NONE;
394 p->to.type = D_NONE;
395 }
396
397 void
398 ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
399 {
400 vlong ipc;
401 Prog *p;
402 int v, o, r, skip, mode;
403 Sym *h[NSYM], *s;
404 uint32 sig;
405 char *name, *x;
406 int ntext;
407 vlong eof;
408 char src[1024];
409 Prog *lastp;
410
411 lastp = nil;
412 ntext = 0;
413 eof = Boffset(f) + len;
414 src[0] = 0;
415
416 newloop:
417 memset(h, 0, sizeof(h));
418 version++;
419 histfrogp = 0;
420 ipc = pc;
421 skip = 0;
422 mode = 64;
423
424 loop:
425 if(f->state == Bracteof || Boffset(f) >= eof)
426 goto eof;
427 o = BGETC(f);
428 if(o == Beof)
429 goto eof;
430 o |= BGETC(f) << 8;
431 if(o <= AXXX || o >= ALAST) {
432 if(o < 0)
433 goto eof;
434 diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
435 print(" probably not a .6 file\n");
436 errorexit();
437 }
438
439 if(o == ANAME || o == ASIGNAME) {
440 sig = 0;
441 if(o == ASIGNAME)
442 sig = Bget4(f);
443 v = BGETC(f); /* type */
444 o = BGETC(f); /* sym */
445 r = 0;
446 if(v == D_STATIC)
447 r = version;
448 name = Brdline(f, '\0');
449 if(name == nil) {
450 if(Blinelen(f) > 0) {
451 fprint(2, "%s: name too long\n", pn);
452 errorexit();
453 }
454 goto eof;
455 }
456 x = expandpkg(name, pkg);
457 s = lookup(x, r);
458 if(x != name)
459 free(x);
460
461 if(debug['S'] && r == 0)
462 sig = 1729;
463 if(sig != 0){
464 if(s->sig != 0 && s->sig != sig)
465 diag("incompatible type signatures"
466 "%ux(%s) and %ux(%s) for %s",
467 s->sig, s->file, sig, pn, s->name);
468 s->sig = sig;
469 s->file = pn;
470 }
471
472 if(debug['W'])
473 print(" ANAME %s\n", s->name);
474 if(o < 0 || o >= nelem(h))
475 mangle(pn);
476 h[o] = s;
477 if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
478 s->type = SXREF;
479 if(v == D_FILE) {
480 if(s->type != SFILE) {
481 histgen++;
482 s->type = SFILE;
483 s->value = histgen;
484 }
485 if(histfrogp < MAXHIST) {
486 histfrog[histfrogp] = s;
487 histfrogp++;
488 } else
489 collapsefrog(s);
490 dwarfaddfrag(s->value, s->name);
491 }
492 goto loop;
493 }
494
495 p = mal(sizeof(*p));
496 p->as = o;
497 p->line = Bget4(f);
498 p->back = 2;
499 p->mode = mode;
500 p->ft = 0;
501 p->tt = 0;
502 zaddr(pn, f, &p->from, h);
503 fromgotype = adrgotype;
504 zaddr(pn, f, &p->to, h);
505
506 switch(p->as) {
507 case ATEXT:
508 case ADATA:
509 case AGLOBL:
510 if(p->from.sym == S)
511 mangle(pn);
512 break;
513 }
514
515 if(debug['W'])
516 print("%P\n", p);
517
518 switch(p->as) {
519 case AHISTORY:
520 if(p->to.offset == -1) {
521 addlib(src, pn);
522 histfrogp = 0;
523 goto loop;
524 }
525 if(src[0] == '\0')
526 copyhistfrog(src, sizeof src);
527 addhist(p->line, D_FILE); /* 'z' */
528 if(p->to.offset)
529 addhist(p->to.offset, D_FILE1); /* 'Z' */
530 histfrogp = 0;
531 goto loop;
532
533 case AEND:
534 histtoauto();
535 if(cursym != nil && cursym->text)
536 cursym->autom = curauto;
537 curauto = 0;
538 cursym = nil;
539 if(Boffset(f) == eof)
540 return;
541 goto newloop;
542
543 case AGLOBL:
544 s = p->from.sym;
545 if(s->type == 0 || s->type == SXREF) {
546 s->type = SBSS;
547 s->size = 0;
548 }
549 if(s->type != SBSS && !s->dupok) {
550 diag("%s: redefinition: %s in %s",
551 pn, s->name, TNAME);
552 s->type = SBSS;
553 s->size = 0;
554 }
555 if(p->to.offset > s->size)
556 s->size = p->to.offset;
557 if(p->from.scale & DUPOK)
558 s->dupok = 1;
559 if(p->from.scale & RODATA)
560 s->type = SRODATA;
561 goto loop;
562
563 case ADATA:
564 // Assume that AGLOBL comes after ADATA.
565 // If we've seen an AGLOBL that said this sym was DUPOK,
566 // ignore any more ADATA we see, which must be
567 // redefinitions.
568 s = p->from.sym;
569 if(s->dupok) {
570 // if(debug['v'])
571 // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
572 goto loop;
573 }
574 if(s->file == nil)
575 s->file = pn;
576 else if(s->file != pn) {
577 diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
578 errorexit();
579 }
580 savedata(s, p, pn);
581 unmal(p, sizeof *p);
582 goto loop;
583
584 case AGOK:
585 diag("%s: GOK opcode in %s", pn, TNAME);
586 pc++;
587 goto loop;
588
589 case ATEXT:
590 s = p->from.sym;
591 if(s->text != nil) {
592 diag("%s: %s: redefinition", pn, s->name);
593 return;
594 }
595 if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
596 /* redefinition, so file has probably been seen before */
597 if(debug['v'])
598 Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
599 return;
600 }
601 if(cursym != nil && cursym->text) {
602 histtoauto();
603 cursym->autom = curauto;
604 curauto = 0;
605 }
606 skip = 0;
607 if(etextp)
608 etextp->next = s;
609 else
610 textp = s;
611 etextp = s;
612 s->text = p;
613 cursym = s;
614 if(s->type != 0 && s->type != SXREF) {
615 if(p->from.scale & DUPOK) {
616 skip = 1;
617 goto casdef;
618 }
619 diag("%s: redefinition: %s\n%P", pn, s->name, p);
620 }
621 if(fromgotype) {
622 if(s->gotype && s->gotype != fromgotype)
623 diag("%s: type mismatch for %s", pn, s->name);
624 s->gotype = fromgotype;
625 }
626 s->type = STEXT;
627 s->value = pc;
628 lastp = p;
629 p->pc = pc++;
630 goto loop;
631
632 case AMODE:
633 if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
634 switch((int)p->from.offset){
635 case 16: case 32: case 64:
636 mode = p->from.offset;
637 break;
638 }
639 }
640 goto loop;
641
642 case AFMOVF:
643 case AFADDF:
644 case AFSUBF:
645 case AFSUBRF:
646 case AFMULF:
647 case AFDIVF:
648 case AFDIVRF:
649 case AFCOMF:
650 case AFCOMFP:
651 case AMOVSS:
652 case AADDSS:
653 case ASUBSS:
654 case AMULSS:
655 case ADIVSS:
656 case ACOMISS:
657 case AUCOMISS:
658 if(skip)
659 goto casdef;
660 if(p->from.type == D_FCONST) {
661 /* size sb 9 max */
662 sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
663 s = lookup(literal, 0);
664 if(s->type == 0) {
665 s->type = SDATA;
666 adduint32(s, ieeedtof(&p->from.ieee));
667 s->reachable = 0;
668 }
669 p->from.type = D_EXTERN;
670 p->from.sym = s;
671 p->from.offset = 0;
672 }
673 goto casdef;
674
675 case AFMOVD:
676 case AFADDD:
677 case AFSUBD:
678 case AFSUBRD:
679 case AFMULD:
680 case AFDIVD:
681 case AFDIVRD:
682 case AFCOMD:
683 case AFCOMDP:
684 case AMOVSD:
685 case AADDSD:
686 case ASUBSD:
687 case AMULSD:
688 case ADIVSD:
689 case ACOMISD:
690 case AUCOMISD:
691 if(skip)
692 goto casdef;
693 if(p->from.type == D_FCONST) {
694 /* size sb 18 max */
695 sprint(literal, "$%ux.%ux",
696 p->from.ieee.l, p->from.ieee.h);
697 s = lookup(literal, 0);
698 if(s->type == 0) {
699 s->type = SDATA;
700 adduint32(s, p->from.ieee.l);
701 adduint32(s, p->from.ieee.h);
702 s->reachable = 0;
703 }
704 p->from.type = D_EXTERN;
705 p->from.sym = s;
706 p->from.offset = 0;
707 }
708 goto casdef;
709
710 casdef:
711 default:
712 if(skip)
713 nopout(p);
714 p->pc = pc;
715 pc++;
716
717 if(p->to.type == D_BRANCH)
718 p->to.offset += ipc;
719 if(lastp == nil) {
720 if(p->as != ANOP)
721 diag("unexpected instruction: %P", p);
722 goto loop;
723 }
724 lastp->link = p;
725 lastp = p;
726 goto loop;
727 }
728
729 eof:
730 diag("truncated object file: %s", pn);
731 }
732
733 Prog*
734 prg(void)
735 {
736 Prog *p;
737
738 p = mal(sizeof(*p));
739
740 *p = zprg;
741 return p;
742 }
743
744 Prog*
745 copyp(Prog *q)
746 {
747 Prog *p;
748
749 p = prg();
750 *p = *q;
751 return p;
752 }
753
754 Prog*
755 appendp(Prog *q)
756 {
757 Prog *p;
758
759 p = prg();
760 p->link = q->link;
761 q->link = p;
762 p->line = q->line;
763 p->mode = q->mode;
764 return p;
765 }