1 // Inferno utils/8l/asm.c
2 // http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
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.
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:
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
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
35 "cmd/link/internal/ld"
40 // Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
41 func addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) {
42 s.Attr |= ld.AttrReachable
45 ld.Symgrow(ctxt, s, s.Size)
54 if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE && ld.Buildmode != ld.BuildmodeCShared {
58 thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)
59 thunkfunc.Type = obj.STEXT
60 thunkfunc.Attr |= ld.AttrLocal
61 thunkfunc.Attr |= ld.AttrReachable
62 o := func(op ...uint8) {
63 for _, op1 := range op {
64 ld.Adduint8(ld.Ctxt, thunkfunc, op1)
67 // 8b 0c 24 mov (%esp),%ecx
72 ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc)
74 addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
75 if addmoduledata.Type == obj.STEXT {
76 // we're linking a module containing the runtime -> no need for
81 addmoduledata.Attr |= ld.AttrReachable
83 initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
84 initfunc.Type = obj.STEXT
85 initfunc.Attr |= ld.AttrLocal
86 initfunc.Attr |= ld.AttrReachable
87 o = func(op ...uint8) {
88 for _, op1 := range op {
89 ld.Adduint8(ld.Ctxt, initfunc, op1)
93 // go.link.addmoduledata:
95 // e8 00 00 00 00 call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx
96 // 8d 81 00 00 00 00 lea 0x0(%ecx), %eax + R_PCREL ld.Ctxt.Moduledata
97 // 8d 99 00 00 00 00 lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_
98 // e8 00 00 00 00 call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata
105 addcall(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0))
108 ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Ctxt.Moduledata, 6)
113 ld.Symgrow(ld.Ctxt, initfunc, initfunc.Size)
114 r := ld.Addrel(initfunc)
115 r.Sym = ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
122 addcall(ld.Ctxt, initfunc, addmoduledata)
128 ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc)
129 initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
130 initarray_entry.Attr |= ld.AttrReachable
131 initarray_entry.Attr |= ld.AttrLocal
132 initarray_entry.Type = obj.SINITARR
133 ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
136 func adddynrel(s *ld.LSym, r *ld.Reloc) {
143 ld.Diag("unexpected relocation type %d", r.Type)
147 // Handle relocations found in ELF object files.
148 case 256 + ld.R_386_PC32:
149 if targ.Type == obj.SDYNIMPORT {
150 ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
152 if targ.Type == 0 || targ.Type == obj.SXREF {
153 ld.Diag("unknown symbol %s in pcrel", targ.Name)
159 case 256 + ld.R_386_PLT32:
162 if targ.Type == obj.SDYNIMPORT {
163 addpltsym(ld.Ctxt, targ)
164 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
165 r.Add += int64(targ.Plt)
170 case 256 + ld.R_386_GOT32, 256 + ld.R_386_GOT32X:
171 if targ.Type != obj.SDYNIMPORT {
173 if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
174 // turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
177 r.Type = obj.R_GOTOFF
181 if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
182 // turn PUSHL of GOT entry into PUSHL of symbol itself.
183 // use unnecessary SS prefix to keep instruction same length.
191 ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
195 addgotsym(ld.Ctxt, targ)
196 r.Type = obj.R_CONST // write r->add during relocsym
198 r.Add += int64(targ.Got)
201 case 256 + ld.R_386_GOTOFF:
202 r.Type = obj.R_GOTOFF
205 case 256 + ld.R_386_GOTPC:
207 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
211 case 256 + ld.R_386_32:
212 if targ.Type == obj.SDYNIMPORT {
213 ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
218 case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
220 if targ.Type == obj.SDYNIMPORT {
221 ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
225 case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
226 if targ.Type == obj.SDYNIMPORT {
227 addpltsym(ld.Ctxt, targ)
228 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
229 r.Add = int64(targ.Plt)
237 case 512 + ld.MACHO_FAKE_GOTPCREL:
238 if targ.Type != obj.SDYNIMPORT {
240 // turn MOVL of GOT entry into LEAL of symbol itself
241 if r.Off < 2 || s.P[r.Off-2] != 0x8b {
242 ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
251 addgotsym(ld.Ctxt, targ)
252 r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
253 r.Add += int64(targ.Got)
258 // Handle references to ELF symbols from our own object files.
259 if targ.Type != obj.SDYNIMPORT {
266 addpltsym(ld.Ctxt, targ)
267 r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
268 r.Add = int64(targ.Plt)
272 if s.Type != obj.SDATA {
276 ld.Adddynsym(ld.Ctxt, targ)
277 rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
278 ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
279 ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
280 r.Type = obj.R_CONST // write r->add during relocsym
285 if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
286 // Mach-O relocations are a royal pain to lay out.
287 // They use a compact stateful bytecode representation
288 // that is too much bother to deal with.
289 // Instead, interpret the C declaration
290 // void *_Cvar_stderr = &stderr;
291 // as making _Cvar_stderr the name of a GOT entry
292 // for stderr. This is separate from the usual GOT entry,
293 // just in case the C code assigns to the variable,
294 // and of course it only works for single pointers,
295 // but we only need to support cgo and that's all it needs.
296 ld.Adddynsym(ld.Ctxt, targ)
298 got := ld.Linklookup(ld.Ctxt, ".got", 0)
299 s.Type = got.Type | obj.SSUB
304 ld.Adduint32(ld.Ctxt, got, 0)
305 ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
306 r.Type = 256 // ignore during relocsym
310 if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
311 // nothing to do, the relocation will be laid out in pereloc1
317 ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
320 func elfreloc1(r *ld.Reloc, sectoff int64) int {
321 ld.Thearch.Lput(uint32(sectoff))
323 elfsym := r.Xsym.ElfsymForReloc()
330 ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
337 ld.Thearch.Lput(ld.R_386_GOTPC)
338 if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
339 ld.Thearch.Lput(uint32(sectoff))
340 ld.Thearch.Lput(ld.R_386_GOT32 | uint32(elfsym)<<8)
348 if r.Xsym.Type == obj.SDYNIMPORT {
349 ld.Thearch.Lput(ld.R_386_PLT32 | uint32(elfsym)<<8)
351 ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
359 ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
366 ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
373 ld.Thearch.Lput(ld.R_386_GOTPC)
374 ld.Thearch.Lput(uint32(sectoff))
375 ld.Thearch.Lput(ld.R_386_TLS_GOTIE | uint32(elfsym)<<8)
384 func machoreloc1(r *ld.Reloc, sectoff int64) int {
389 if rs.Type == obj.SHOSTOBJ {
391 ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
396 v |= 1 << 27 // external relocation
398 v = uint32(rs.Sect.Extnum)
400 ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
410 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
414 v |= 1 << 24 // pc-relative bit
415 v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
435 ld.Thearch.Lput(uint32(sectoff))
440 func pereloc1(r *ld.Reloc, sectoff int64) bool {
446 ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
450 ld.Thearch.Lput(uint32(sectoff))
451 ld.Thearch.Lput(uint32(rs.Dynid))
458 v = ld.IMAGE_REL_I386_DIR32
462 v = ld.IMAGE_REL_I386_REL32
465 ld.Thearch.Wput(uint16(v))
470 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
471 if ld.Linkmode == ld.LinkExternal {
480 *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
487 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
488 log.Fatalf("unexpected relocation variant")
493 plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
494 got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
497 ld.Adduint8(ld.Ctxt, plt, 0xff)
499 ld.Adduint8(ld.Ctxt, plt, 0x35)
500 ld.Addaddrplus(ld.Ctxt, plt, got, 4)
503 ld.Adduint8(ld.Ctxt, plt, 0xff)
505 ld.Adduint8(ld.Ctxt, plt, 0x25)
506 ld.Addaddrplus(ld.Ctxt, plt, got, 8)
509 ld.Adduint32(ld.Ctxt, plt, 0)
511 // assume got->size == 0 too
512 ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
514 ld.Adduint32(ld.Ctxt, got, 0)
515 ld.Adduint32(ld.Ctxt, got, 0)
519 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
524 ld.Adddynsym(ctxt, s)
527 plt := ld.Linklookup(ctxt, ".plt", 0)
528 got := ld.Linklookup(ctxt, ".got.plt", 0)
529 rel := ld.Linklookup(ctxt, ".rel.plt", 0)
535 ld.Adduint8(ctxt, plt, 0xff)
537 ld.Adduint8(ctxt, plt, 0x25)
538 ld.Addaddrplus(ctxt, plt, got, got.Size)
540 // add to got: pointer to current pos in plt
541 ld.Addaddrplus(ctxt, got, plt, plt.Size)
544 ld.Adduint8(ctxt, plt, 0x68)
546 ld.Adduint32(ctxt, plt, uint32(rel.Size))
549 ld.Adduint8(ctxt, plt, 0xe9)
551 ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
554 ld.Addaddrplus(ctxt, rel, got, got.Size-4)
556 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
558 s.Plt = int32(plt.Size - 16)
559 } else if ld.HEADTYPE == obj.Hdarwin {
560 // Same laziness as in 6l.
562 plt := ld.Linklookup(ctxt, ".plt", 0)
566 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
568 // jmpq *got+size(IP)
569 s.Plt = int32(plt.Size)
571 ld.Adduint8(ctxt, plt, 0xff)
572 ld.Adduint8(ctxt, plt, 0x25)
573 ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
575 ld.Diag("addpltsym: unsupported binary format")
579 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
584 ld.Adddynsym(ctxt, s)
585 got := ld.Linklookup(ctxt, ".got", 0)
586 s.Got = int32(got.Size)
587 ld.Adduint32(ctxt, got, 0)
590 rel := ld.Linklookup(ctxt, ".rel", 0)
591 ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
592 ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
593 } else if ld.HEADTYPE == obj.Hdarwin {
594 ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
596 ld.Diag("addgotsym: unsupported binary format")
601 if ld.Debug['v'] != 0 {
602 fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime())
610 sect := ld.Segtext.Sect
611 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
612 ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
613 for sect = sect.Next; sect != nil; sect = sect.Next {
614 ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
615 ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
618 if ld.Segrodata.Filelen > 0 {
619 if ld.Debug['v'] != 0 {
620 fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
624 ld.Cseek(int64(ld.Segrodata.Fileoff))
625 ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
628 if ld.Debug['v'] != 0 {
629 fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime())
633 ld.Cseek(int64(ld.Segdata.Fileoff))
634 ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
636 ld.Cseek(int64(ld.Segdwarf.Fileoff))
637 ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
639 machlink := uint32(0)
640 if ld.HEADTYPE == obj.Hdarwin {
641 machlink = uint32(ld.Domacholink())
648 if ld.Debug['s'] == 0 {
650 if ld.Debug['v'] != 0 {
651 fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime())
657 symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
658 symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
662 symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
665 symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
668 symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
669 symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
672 ld.Cseek(int64(symo))
676 if ld.Debug['v'] != 0 {
677 fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime())
681 ld.Cwrite(ld.Elfstrdat)
683 if ld.Linkmode == ld.LinkExternal {
692 sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
694 ld.Lcsize = int32(len(sym.P))
695 for i := 0; int32(i) < ld.Lcsize; i++ {
703 if ld.Debug['v'] != 0 {
704 fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime())
708 if ld.Linkmode == ld.LinkExternal {
714 if ld.Debug['v'] != 0 {
715 fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime())
721 case obj.Hplan9: /* plan9 */
722 magic := int32(4*11*11 + 7)
724 ld.Lputb(uint32(magic)) /* magic */
725 ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
726 ld.Lputb(uint32(ld.Segdata.Filelen))
727 ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
728 ld.Lputb(uint32(ld.Symsize)) /* nsyms */
729 ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
730 ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
731 ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
741 ld.Asmbelf(int64(symo))