...

Source file src/pkg/cmd/link/internal/x86/asm.go

     1	// Inferno utils/8l/asm.c
     2	// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.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	package x86
    32	
    33	import (
    34		"cmd/internal/objabi"
    35		"cmd/internal/sys"
    36		"cmd/link/internal/ld"
    37		"cmd/link/internal/sym"
    38		"debug/elf"
    39		"log"
    40	)
    41	
    42	// Append 4 bytes to s and create a R_CALL relocation targeting t to fill them in.
    43	func addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) {
    44		s.Attr |= sym.AttrReachable
    45		i := s.Size
    46		s.Size += 4
    47		s.Grow(s.Size)
    48		r := s.AddRel()
    49		r.Sym = t
    50		r.Off = int32(i)
    51		r.Type = objabi.R_CALL
    52		r.Siz = 4
    53	}
    54	
    55	func gentext(ctxt *ld.Link) {
    56		if ctxt.DynlinkingGo() {
    57			// We need get_pc_thunk.
    58		} else {
    59			switch ctxt.BuildMode {
    60			case ld.BuildModeCArchive:
    61				if !ctxt.IsELF {
    62					return
    63				}
    64			case ld.BuildModePIE, ld.BuildModeCShared, ld.BuildModePlugin:
    65				// We need get_pc_thunk.
    66			default:
    67				return
    68			}
    69		}
    70	
    71		// Generate little thunks that load the PC of the next instruction into a register.
    72		thunks := make([]*sym.Symbol, 0, 7+len(ctxt.Textp))
    73		for _, r := range [...]struct {
    74			name string
    75			num  uint8
    76		}{
    77			{"ax", 0},
    78			{"cx", 1},
    79			{"dx", 2},
    80			{"bx", 3},
    81			// sp
    82			{"bp", 5},
    83			{"si", 6},
    84			{"di", 7},
    85		} {
    86			thunkfunc := ctxt.Syms.Lookup("__x86.get_pc_thunk."+r.name, 0)
    87			thunkfunc.Type = sym.STEXT
    88			thunkfunc.Attr |= sym.AttrLocal
    89			thunkfunc.Attr |= sym.AttrReachable //TODO: remove?
    90			o := func(op ...uint8) {
    91				for _, op1 := range op {
    92					thunkfunc.AddUint8(op1)
    93				}
    94			}
    95			// 8b 04 24	mov    (%esp),%eax
    96			// Destination register is in bits 3-5 of the middle byte, so add that in.
    97			o(0x8b, 0x04+r.num<<3, 0x24)
    98			// c3		ret
    99			o(0xc3)
   100	
   101			thunks = append(thunks, thunkfunc)
   102		}
   103		ctxt.Textp = append(thunks, ctxt.Textp...) // keep Textp in dependency order
   104	
   105		addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
   106		if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
   107			// we're linking a module containing the runtime -> no need for
   108			// an init function
   109			return
   110		}
   111	
   112		addmoduledata.Attr |= sym.AttrReachable
   113	
   114		initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
   115		initfunc.Type = sym.STEXT
   116		initfunc.Attr |= sym.AttrLocal
   117		initfunc.Attr |= sym.AttrReachable
   118		o := func(op ...uint8) {
   119			for _, op1 := range op {
   120				initfunc.AddUint8(op1)
   121			}
   122		}
   123	
   124		// go.link.addmoduledata:
   125		//      53                      push %ebx
   126		//      e8 00 00 00 00          call __x86.get_pc_thunk.cx + R_CALL __x86.get_pc_thunk.cx
   127		//      8d 81 00 00 00 00       lea 0x0(%ecx), %eax + R_PCREL ctxt.Moduledata
   128		//      8d 99 00 00 00 00       lea 0x0(%ecx), %ebx + R_GOTPC _GLOBAL_OFFSET_TABLE_
   129		//      e8 00 00 00 00          call runtime.addmoduledata@plt + R_CALL runtime.addmoduledata
   130		//      5b                      pop %ebx
   131		//      c3                      ret
   132	
   133		o(0x53)
   134	
   135		o(0xe8)
   136		addcall(ctxt, initfunc, ctxt.Syms.Lookup("__x86.get_pc_thunk.cx", 0))
   137	
   138		o(0x8d, 0x81)
   139		initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6)
   140	
   141		o(0x8d, 0x99)
   142		i := initfunc.Size
   143		initfunc.Size += 4
   144		initfunc.Grow(initfunc.Size)
   145		r := initfunc.AddRel()
   146		r.Sym = ctxt.Syms.Lookup("_GLOBAL_OFFSET_TABLE_", 0)
   147		r.Off = int32(i)
   148		r.Type = objabi.R_PCREL
   149		r.Add = 12
   150		r.Siz = 4
   151	
   152		o(0xe8)
   153		addcall(ctxt, initfunc, addmoduledata)
   154	
   155		o(0x5b)
   156	
   157		o(0xc3)
   158	
   159		if ctxt.BuildMode == ld.BuildModePlugin {
   160			ctxt.Textp = append(ctxt.Textp, addmoduledata)
   161		}
   162		ctxt.Textp = append(ctxt.Textp, initfunc)
   163		initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
   164		initarray_entry.Attr |= sym.AttrReachable
   165		initarray_entry.Attr |= sym.AttrLocal
   166		initarray_entry.Type = sym.SINITARR
   167		initarray_entry.AddAddr(ctxt.Arch, initfunc)
   168	}
   169	
   170	func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
   171		targ := r.Sym
   172	
   173		switch r.Type {
   174		default:
   175			if r.Type >= objabi.ElfRelocOffset {
   176				ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   177				return false
   178			}
   179	
   180			// Handle relocations found in ELF object files.
   181		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
   182			if targ.Type == sym.SDYNIMPORT {
   183				ld.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
   184			}
   185			// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
   186			// sense and should be removed when someone has thought about it properly.
   187			if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
   188				ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
   189			}
   190			r.Type = objabi.R_PCREL
   191			r.Add += 4
   192			return true
   193	
   194		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
   195			r.Type = objabi.R_PCREL
   196			r.Add += 4
   197			if targ.Type == sym.SDYNIMPORT {
   198				addpltsym(ctxt, targ)
   199				r.Sym = ctxt.Syms.Lookup(".plt", 0)
   200				r.Add += int64(targ.Plt())
   201			}
   202	
   203			return true
   204	
   205		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
   206			objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
   207			if targ.Type != sym.SDYNIMPORT {
   208				// have symbol
   209				if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
   210					// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
   211					s.P[r.Off-2] = 0x8d
   212	
   213					r.Type = objabi.R_GOTOFF
   214					return true
   215				}
   216	
   217				if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
   218					// turn PUSHL of GOT entry into PUSHL of symbol itself.
   219					// use unnecessary SS prefix to keep instruction same length.
   220					s.P[r.Off-2] = 0x36
   221	
   222					s.P[r.Off-1] = 0x68
   223					r.Type = objabi.R_ADDR
   224					return true
   225				}
   226	
   227				ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
   228				return false
   229			}
   230	
   231			addgotsym(ctxt, targ)
   232			r.Type = objabi.R_CONST // write r->add during relocsym
   233			r.Sym = nil
   234			r.Add += int64(targ.Got())
   235			return true
   236	
   237		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
   238			r.Type = objabi.R_GOTOFF
   239			return true
   240	
   241		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
   242			r.Type = objabi.R_PCREL
   243			r.Sym = ctxt.Syms.Lookup(".got", 0)
   244			r.Add += 4
   245			return true
   246	
   247		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
   248			if targ.Type == sym.SDYNIMPORT {
   249				ld.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
   250			}
   251			r.Type = objabi.R_ADDR
   252			return true
   253	
   254		case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
   255			r.Type = objabi.R_ADDR
   256			if targ.Type == sym.SDYNIMPORT {
   257				ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
   258			}
   259			return true
   260	
   261		case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
   262			if targ.Type == sym.SDYNIMPORT {
   263				addpltsym(ctxt, targ)
   264				r.Sym = ctxt.Syms.Lookup(".plt", 0)
   265				r.Add = int64(targ.Plt())
   266				r.Type = objabi.R_PCREL
   267				return true
   268			}
   269	
   270			r.Type = objabi.R_PCREL
   271			return true
   272	
   273		case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
   274			if targ.Type != sym.SDYNIMPORT {
   275				// have symbol
   276				// turn MOVL of GOT entry into LEAL of symbol itself
   277				if r.Off < 2 || s.P[r.Off-2] != 0x8b {
   278					ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
   279					return false
   280				}
   281	
   282				s.P[r.Off-2] = 0x8d
   283				r.Type = objabi.R_PCREL
   284				return true
   285			}
   286	
   287			addgotsym(ctxt, targ)
   288			r.Sym = ctxt.Syms.Lookup(".got", 0)
   289			r.Add += int64(targ.Got())
   290			r.Type = objabi.R_PCREL
   291			return true
   292		}
   293	
   294		// Handle references to ELF symbols from our own object files.
   295		if targ.Type != sym.SDYNIMPORT {
   296			return true
   297		}
   298		switch r.Type {
   299		case objabi.R_CALL,
   300			objabi.R_PCREL:
   301			if ctxt.LinkMode == ld.LinkExternal {
   302				// External linker will do this relocation.
   303				return true
   304			}
   305			addpltsym(ctxt, targ)
   306			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   307			r.Add = int64(targ.Plt())
   308			return true
   309	
   310		case objabi.R_ADDR:
   311			if s.Type != sym.SDATA {
   312				break
   313			}
   314			if ctxt.IsELF {
   315				ld.Adddynsym(ctxt, targ)
   316				rel := ctxt.Syms.Lookup(".rel", 0)
   317				rel.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
   318				rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(targ.Dynid), uint32(elf.R_386_32)))
   319				r.Type = objabi.R_CONST // write r->add during relocsym
   320				r.Sym = nil
   321				return true
   322			}
   323	
   324			if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 {
   325				// Mach-O relocations are a royal pain to lay out.
   326				// They use a compact stateful bytecode representation
   327				// that is too much bother to deal with.
   328				// Instead, interpret the C declaration
   329				//	void *_Cvar_stderr = &stderr;
   330				// as making _Cvar_stderr the name of a GOT entry
   331				// for stderr. This is separate from the usual GOT entry,
   332				// just in case the C code assigns to the variable,
   333				// and of course it only works for single pointers,
   334				// but we only need to support cgo and that's all it needs.
   335				ld.Adddynsym(ctxt, targ)
   336	
   337				got := ctxt.Syms.Lookup(".got", 0)
   338				s.Type = got.Type
   339				s.Attr |= sym.AttrSubSymbol
   340				s.Outer = got
   341				s.Sub = got.Sub
   342				got.Sub = s
   343				s.Value = got.Size
   344				got.AddUint32(ctxt.Arch, 0)
   345				ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid))
   346				r.Type = objabi.ElfRelocOffset // ignore during relocsym
   347				return true
   348			}
   349		}
   350	
   351		return false
   352	}
   353	
   354	func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   355		ctxt.Out.Write32(uint32(sectoff))
   356	
   357		elfsym := r.Xsym.ElfsymForReloc()
   358		switch r.Type {
   359		default:
   360			return false
   361		case objabi.R_ADDR:
   362			if r.Siz == 4 {
   363				ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
   364			} else {
   365				return false
   366			}
   367		case objabi.R_GOTPCREL:
   368			if r.Siz == 4 {
   369				ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
   370				if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
   371					ctxt.Out.Write32(uint32(sectoff))
   372					ctxt.Out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8)
   373				}
   374			} else {
   375				return false
   376			}
   377		case objabi.R_CALL:
   378			if r.Siz == 4 {
   379				if r.Xsym.Type == sym.SDYNIMPORT {
   380					ctxt.Out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8)
   381				} else {
   382					ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
   383				}
   384			} else {
   385				return false
   386			}
   387		case objabi.R_PCREL:
   388			if r.Siz == 4 {
   389				ctxt.Out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
   390			} else {
   391				return false
   392			}
   393		case objabi.R_TLS_LE:
   394			if r.Siz == 4 {
   395				ctxt.Out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8)
   396			} else {
   397				return false
   398			}
   399		case objabi.R_TLS_IE:
   400			if r.Siz == 4 {
   401				ctxt.Out.Write32(uint32(elf.R_386_GOTPC))
   402				ctxt.Out.Write32(uint32(sectoff))
   403				ctxt.Out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8)
   404			} else {
   405				return false
   406			}
   407		}
   408	
   409		return true
   410	}
   411	
   412	func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   413		var v uint32
   414	
   415		rs := r.Xsym
   416	
   417		if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_CALL {
   418			if rs.Dynid < 0 {
   419				ld.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
   420				return false
   421			}
   422	
   423			v = uint32(rs.Dynid)
   424			v |= 1 << 27 // external relocation
   425		} else {
   426			v = uint32(rs.Sect.Extnum)
   427			if v == 0 {
   428				ld.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Sect.Name, rs.Type, rs.Type)
   429				return false
   430			}
   431		}
   432	
   433		switch r.Type {
   434		default:
   435			return false
   436		case objabi.R_ADDR:
   437			v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
   438		case objabi.R_CALL,
   439			objabi.R_PCREL:
   440			v |= 1 << 24 // pc-relative bit
   441			v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
   442		}
   443	
   444		switch r.Siz {
   445		default:
   446			return false
   447		case 1:
   448			v |= 0 << 25
   449		case 2:
   450			v |= 1 << 25
   451		case 4:
   452			v |= 2 << 25
   453		case 8:
   454			v |= 3 << 25
   455		}
   456	
   457		out.Write32(uint32(sectoff))
   458		out.Write32(v)
   459		return true
   460	}
   461	
   462	func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   463		var v uint32
   464	
   465		rs := r.Xsym
   466	
   467		if rs.Dynid < 0 {
   468			ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
   469			return false
   470		}
   471	
   472		out.Write32(uint32(sectoff))
   473		out.Write32(uint32(rs.Dynid))
   474	
   475		switch r.Type {
   476		default:
   477			return false
   478	
   479		case objabi.R_DWARFSECREF:
   480			v = ld.IMAGE_REL_I386_SECREL
   481	
   482		case objabi.R_ADDR:
   483			v = ld.IMAGE_REL_I386_DIR32
   484	
   485		case objabi.R_CALL,
   486			objabi.R_PCREL:
   487			v = ld.IMAGE_REL_I386_REL32
   488		}
   489	
   490		out.Write16(uint16(v))
   491	
   492		return true
   493	}
   494	
   495	func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
   496		if ctxt.LinkMode == ld.LinkExternal {
   497			return val, false
   498		}
   499		switch r.Type {
   500		case objabi.R_CONST:
   501			return r.Add, true
   502		case objabi.R_GOTOFF:
   503			return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
   504		}
   505	
   506		return val, false
   507	}
   508	
   509	func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   510		log.Fatalf("unexpected relocation variant")
   511		return t
   512	}
   513	
   514	func elfsetupplt(ctxt *ld.Link) {
   515		plt := ctxt.Syms.Lookup(".plt", 0)
   516		got := ctxt.Syms.Lookup(".got.plt", 0)
   517		if plt.Size == 0 {
   518			// pushl got+4
   519			plt.AddUint8(0xff)
   520	
   521			plt.AddUint8(0x35)
   522			plt.AddAddrPlus(ctxt.Arch, got, 4)
   523	
   524			// jmp *got+8
   525			plt.AddUint8(0xff)
   526	
   527			plt.AddUint8(0x25)
   528			plt.AddAddrPlus(ctxt.Arch, got, 8)
   529	
   530			// zero pad
   531			plt.AddUint32(ctxt.Arch, 0)
   532	
   533			// assume got->size == 0 too
   534			got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
   535	
   536			got.AddUint32(ctxt.Arch, 0)
   537			got.AddUint32(ctxt.Arch, 0)
   538		}
   539	}
   540	
   541	func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
   542		if s.Plt() >= 0 {
   543			return
   544		}
   545	
   546		ld.Adddynsym(ctxt, s)
   547	
   548		if ctxt.IsELF {
   549			plt := ctxt.Syms.Lookup(".plt", 0)
   550			got := ctxt.Syms.Lookup(".got.plt", 0)
   551			rel := ctxt.Syms.Lookup(".rel.plt", 0)
   552			if plt.Size == 0 {
   553				elfsetupplt(ctxt)
   554			}
   555	
   556			// jmpq *got+size
   557			plt.AddUint8(0xff)
   558	
   559			plt.AddUint8(0x25)
   560			plt.AddAddrPlus(ctxt.Arch, got, got.Size)
   561	
   562			// add to got: pointer to current pos in plt
   563			got.AddAddrPlus(ctxt.Arch, plt, plt.Size)
   564	
   565			// pushl $x
   566			plt.AddUint8(0x68)
   567	
   568			plt.AddUint32(ctxt.Arch, uint32(rel.Size))
   569	
   570			// jmp .plt
   571			plt.AddUint8(0xe9)
   572	
   573			plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4)))
   574	
   575			// rel
   576			rel.AddAddrPlus(ctxt.Arch, got, got.Size-4)
   577	
   578			rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT)))
   579	
   580			s.SetPlt(int32(plt.Size - 16))
   581		} else if ctxt.HeadType == objabi.Hdarwin {
   582			// Same laziness as in 6l.
   583	
   584			plt := ctxt.Syms.Lookup(".plt", 0)
   585	
   586			addgotsym(ctxt, s)
   587	
   588			ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   589	
   590			// jmpq *got+size(IP)
   591			s.SetPlt(int32(plt.Size))
   592	
   593			plt.AddUint8(0xff)
   594			plt.AddUint8(0x25)
   595			plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got()))
   596		} else {
   597			ld.Errorf(s, "addpltsym: unsupported binary format")
   598		}
   599	}
   600	
   601	func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
   602		if s.Got() >= 0 {
   603			return
   604		}
   605	
   606		ld.Adddynsym(ctxt, s)
   607		got := ctxt.Syms.Lookup(".got", 0)
   608		s.SetGot(int32(got.Size))
   609		got.AddUint32(ctxt.Arch, 0)
   610	
   611		if ctxt.IsELF {
   612			rel := ctxt.Syms.Lookup(".rel", 0)
   613			rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
   614			rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT)))
   615		} else if ctxt.HeadType == objabi.Hdarwin {
   616			ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   617		} else {
   618			ld.Errorf(s, "addgotsym: unsupported binary format")
   619		}
   620	}
   621	
   622	func asmb(ctxt *ld.Link) {
   623		if ctxt.Debugvlog != 0 {
   624			ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   625		}
   626	
   627		if ctxt.IsELF {
   628			ld.Asmbelfsetup()
   629		}
   630	
   631		sect := ld.Segtext.Sections[0]
   632		ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   633		// 0xCC is INT $3 - breakpoint instruction
   634		ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
   635		for _, sect = range ld.Segtext.Sections[1:] {
   636			ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   637			ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   638		}
   639	
   640		if ld.Segrodata.Filelen > 0 {
   641			if ctxt.Debugvlog != 0 {
   642				ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   643			}
   644	
   645			ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
   646			ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   647		}
   648		if ld.Segrelrodata.Filelen > 0 {
   649			if ctxt.Debugvlog != 0 {
   650				ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   651			}
   652			ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
   653			ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   654		}
   655	
   656		if ctxt.Debugvlog != 0 {
   657			ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   658		}
   659	
   660		ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   661		ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   662	
   663		ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
   664		ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   665	}
   666	
   667	func asmb2(ctxt *ld.Link) {
   668		machlink := uint32(0)
   669		if ctxt.HeadType == objabi.Hdarwin {
   670			machlink = uint32(ld.Domacholink(ctxt))
   671		}
   672	
   673		ld.Symsize = 0
   674		ld.Spsize = 0
   675		ld.Lcsize = 0
   676		symo := uint32(0)
   677		if !*ld.FlagS {
   678			// TODO: rationalize
   679			if ctxt.Debugvlog != 0 {
   680				ctxt.Logf("%5.2f sym\n", ld.Cputime())
   681			}
   682			switch ctxt.HeadType {
   683			default:
   684				if ctxt.IsELF {
   685					symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   686					symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   687				}
   688	
   689			case objabi.Hplan9:
   690				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   691	
   692			case objabi.Hdarwin:
   693				symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
   694	
   695			case objabi.Hwindows:
   696				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   697				symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
   698			}
   699	
   700			ctxt.Out.SeekSet(int64(symo))
   701			switch ctxt.HeadType {
   702			default:
   703				if ctxt.IsELF {
   704					if ctxt.Debugvlog != 0 {
   705						ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   706					}
   707					ld.Asmelfsym(ctxt)
   708					ctxt.Out.Flush()
   709					ctxt.Out.Write(ld.Elfstrdat)
   710	
   711					if ctxt.LinkMode == ld.LinkExternal {
   712						ld.Elfemitreloc(ctxt)
   713					}
   714				}
   715	
   716			case objabi.Hplan9:
   717				ld.Asmplan9sym(ctxt)
   718				ctxt.Out.Flush()
   719	
   720				sym := ctxt.Syms.Lookup("pclntab", 0)
   721				if sym != nil {
   722					ld.Lcsize = int32(len(sym.P))
   723					ctxt.Out.Write(sym.P)
   724					ctxt.Out.Flush()
   725				}
   726	
   727			case objabi.Hwindows:
   728				if ctxt.Debugvlog != 0 {
   729					ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
   730				}
   731	
   732			case objabi.Hdarwin:
   733				if ctxt.LinkMode == ld.LinkExternal {
   734					ld.Machoemitreloc(ctxt)
   735				}
   736			}
   737		}
   738	
   739		if ctxt.Debugvlog != 0 {
   740			ctxt.Logf("%5.2f headr\n", ld.Cputime())
   741		}
   742		ctxt.Out.SeekSet(0)
   743		switch ctxt.HeadType {
   744		default:
   745		case objabi.Hplan9: /* plan9 */
   746			magic := int32(4*11*11 + 7)
   747	
   748			ctxt.Out.Write32b(uint32(magic))              /* magic */
   749			ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
   750			ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
   751			ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   752			ctxt.Out.Write32b(uint32(ld.Symsize))          /* nsyms */
   753			ctxt.Out.Write32b(uint32(ld.Entryvalue(ctxt))) /* va of entry */
   754			ctxt.Out.Write32b(uint32(ld.Spsize))           /* sp offsets */
   755			ctxt.Out.Write32b(uint32(ld.Lcsize))           /* line offsets */
   756	
   757		case objabi.Hdarwin:
   758			ld.Asmbmacho(ctxt)
   759	
   760		case objabi.Hlinux,
   761			objabi.Hfreebsd,
   762			objabi.Hnetbsd,
   763			objabi.Hopenbsd,
   764			objabi.Hnacl:
   765			ld.Asmbelf(ctxt, int64(symo))
   766	
   767		case objabi.Hwindows:
   768			ld.Asmbpe(ctxt)
   769		}
   770	
   771		ctxt.Out.Flush()
   772	}
   773	

View as plain text