...

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

     1	// Inferno utils/6l/asm.c
     2	// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/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 amd64
    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	func PADDR(x uint32) uint32 {
    43		return x &^ 0x80000000
    44	}
    45	
    46	func Addcall(ctxt *ld.Link, s *sym.Symbol, t *sym.Symbol) int64 {
    47		s.Attr |= sym.AttrReachable
    48		i := s.Size
    49		s.Size += 4
    50		s.Grow(s.Size)
    51		r := s.AddRel()
    52		r.Sym = t
    53		r.Off = int32(i)
    54		r.Type = objabi.R_CALL
    55		r.Siz = 4
    56		return i + int64(r.Siz)
    57	}
    58	
    59	func gentext(ctxt *ld.Link) {
    60		if !ctxt.DynlinkingGo() {
    61			return
    62		}
    63		addmoduledata := ctxt.Syms.Lookup("runtime.addmoduledata", 0)
    64		if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
    65			// we're linking a module containing the runtime -> no need for
    66			// an init function
    67			return
    68		}
    69		addmoduledata.Attr |= sym.AttrReachable
    70		initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
    71		initfunc.Type = sym.STEXT
    72		initfunc.Attr |= sym.AttrLocal
    73		initfunc.Attr |= sym.AttrReachable
    74		o := func(op ...uint8) {
    75			for _, op1 := range op {
    76				initfunc.AddUint8(op1)
    77			}
    78		}
    79		// 0000000000000000 <local.dso_init>:
    80		//    0:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 7 <local.dso_init+0x7>
    81		// 			3: R_X86_64_PC32	runtime.firstmoduledata-0x4
    82		o(0x48, 0x8d, 0x3d)
    83		initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0)
    84		//    7:	e8 00 00 00 00       	callq  c <local.dso_init+0xc>
    85		// 			8: R_X86_64_PLT32	runtime.addmoduledata-0x4
    86		o(0xe8)
    87		Addcall(ctxt, initfunc, addmoduledata)
    88		//    c:	c3                   	retq
    89		o(0xc3)
    90		if ctxt.BuildMode == ld.BuildModePlugin {
    91			ctxt.Textp = append(ctxt.Textp, addmoduledata)
    92		}
    93		ctxt.Textp = append(ctxt.Textp, initfunc)
    94		initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
    95		initarray_entry.Attr |= sym.AttrReachable
    96		initarray_entry.Attr |= sym.AttrLocal
    97		initarray_entry.Type = sym.SINITARR
    98		initarray_entry.AddAddr(ctxt.Arch, initfunc)
    99	}
   100	
   101	func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
   102		targ := r.Sym
   103	
   104		switch r.Type {
   105		default:
   106			if r.Type >= objabi.ElfRelocOffset {
   107				ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   108				return false
   109			}
   110	
   111			// Handle relocations found in ELF object files.
   112		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
   113			if targ.Type == sym.SDYNIMPORT {
   114				ld.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
   115			}
   116			// TODO(mwhudson): the test of VisibilityHidden here probably doesn't make
   117			// sense and should be removed when someone has thought about it properly.
   118			if (targ.Type == 0 || targ.Type == sym.SXREF) && !targ.Attr.VisibilityHidden() {
   119				ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
   120			}
   121			r.Type = objabi.R_PCREL
   122			r.Add += 4
   123			return true
   124	
   125		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
   126			if targ.Type == sym.SDYNIMPORT {
   127				ld.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", targ.Name)
   128			}
   129			if targ.Type == 0 || targ.Type == sym.SXREF {
   130				ld.Errorf(s, "unknown symbol %s in pcrel", targ.Name)
   131			}
   132			r.Type = objabi.R_PCREL
   133			r.Add += 8
   134			return true
   135	
   136		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
   137			r.Type = objabi.R_PCREL
   138			r.Add += 4
   139			if targ.Type == sym.SDYNIMPORT {
   140				addpltsym(ctxt, targ)
   141				r.Sym = ctxt.Syms.Lookup(".plt", 0)
   142				r.Add += int64(targ.Plt())
   143			}
   144	
   145			return true
   146	
   147		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
   148			objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
   149			objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
   150			if targ.Type != sym.SDYNIMPORT {
   151				// have symbol
   152				if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
   153					// turn MOVQ of GOT entry into LEAQ of symbol itself
   154					s.P[r.Off-2] = 0x8d
   155	
   156					r.Type = objabi.R_PCREL
   157					r.Add += 4
   158					return true
   159				}
   160			}
   161	
   162			// fall back to using GOT and hope for the best (CMOV*)
   163			// TODO: just needs relocation, no need to put in .dynsym
   164			addgotsym(ctxt, targ)
   165	
   166			r.Type = objabi.R_PCREL
   167			r.Sym = ctxt.Syms.Lookup(".got", 0)
   168			r.Add += 4
   169			r.Add += int64(targ.Got())
   170			return true
   171	
   172		case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
   173			if targ.Type == sym.SDYNIMPORT {
   174				ld.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
   175			}
   176			r.Type = objabi.R_ADDR
   177			return true
   178	
   179		// Handle relocations found in Mach-O object files.
   180		case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
   181			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
   182			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
   183			// TODO: What is the difference between all these?
   184			r.Type = objabi.R_ADDR
   185	
   186			if targ.Type == sym.SDYNIMPORT {
   187				ld.Errorf(s, "unexpected reloc for dynamic symbol %s", targ.Name)
   188			}
   189			return true
   190	
   191		case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
   192			if targ.Type == sym.SDYNIMPORT {
   193				addpltsym(ctxt, targ)
   194				r.Sym = ctxt.Syms.Lookup(".plt", 0)
   195				r.Add = int64(targ.Plt())
   196				r.Type = objabi.R_PCREL
   197				return true
   198			}
   199			fallthrough
   200	
   201		case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
   202			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
   203			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
   204			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
   205			objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
   206			r.Type = objabi.R_PCREL
   207	
   208			if targ.Type == sym.SDYNIMPORT {
   209				ld.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
   210			}
   211			return true
   212	
   213		case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
   214			if targ.Type != sym.SDYNIMPORT {
   215				// have symbol
   216				// turn MOVQ of GOT entry into LEAQ of symbol itself
   217				if r.Off < 2 || s.P[r.Off-2] != 0x8b {
   218					ld.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
   219					return false
   220				}
   221	
   222				s.P[r.Off-2] = 0x8d
   223				r.Type = objabi.R_PCREL
   224				return true
   225			}
   226			fallthrough
   227	
   228		case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
   229			if targ.Type != sym.SDYNIMPORT {
   230				ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
   231			}
   232			addgotsym(ctxt, targ)
   233			r.Type = objabi.R_PCREL
   234			r.Sym = ctxt.Syms.Lookup(".got", 0)
   235			r.Add += int64(targ.Got())
   236			return true
   237		}
   238	
   239		switch r.Type {
   240		case objabi.R_CALL,
   241			objabi.R_PCREL:
   242			if targ.Type != sym.SDYNIMPORT {
   243				// nothing to do, the relocation will be laid out in reloc
   244				return true
   245			}
   246			if ctxt.LinkMode == ld.LinkExternal {
   247				// External linker will do this relocation.
   248				return true
   249			}
   250			// Internal linking, for both ELF and Mach-O.
   251			// Build a PLT entry and change the relocation target to that entry.
   252			addpltsym(ctxt, targ)
   253			r.Sym = ctxt.Syms.Lookup(".plt", 0)
   254			r.Add = int64(targ.Plt())
   255			return true
   256	
   257		case objabi.R_ADDR:
   258			if s.Type == sym.STEXT && ctxt.IsELF {
   259				if ctxt.HeadType == objabi.Hsolaris {
   260					addpltsym(ctxt, targ)
   261					r.Sym = ctxt.Syms.Lookup(".plt", 0)
   262					r.Add += int64(targ.Plt())
   263					return true
   264				}
   265				// The code is asking for the address of an external
   266				// function. We provide it with the address of the
   267				// correspondent GOT symbol.
   268				addgotsym(ctxt, targ)
   269	
   270				r.Sym = ctxt.Syms.Lookup(".got", 0)
   271				r.Add += int64(targ.Got())
   272				return true
   273			}
   274	
   275			// Process dynamic relocations for the data sections.
   276			if ctxt.BuildMode == ld.BuildModePIE && ctxt.LinkMode == ld.LinkInternal {
   277				// When internally linking, generate dynamic relocations
   278				// for all typical R_ADDR relocations. The exception
   279				// are those R_ADDR that are created as part of generating
   280				// the dynamic relocations and must be resolved statically.
   281				//
   282				// There are three phases relevant to understanding this:
   283				//
   284				//	dodata()  // we are here
   285				//	address() // symbol address assignment
   286				//	reloc()   // resolution of static R_ADDR relocs
   287				//
   288				// At this point symbol addresses have not been
   289				// assigned yet (as the final size of the .rela section
   290				// will affect the addresses), and so we cannot write
   291				// the Elf64_Rela.r_offset now. Instead we delay it
   292				// until after the 'address' phase of the linker is
   293				// complete. We do this via Addaddrplus, which creates
   294				// a new R_ADDR relocation which will be resolved in
   295				// the 'reloc' phase.
   296				//
   297				// These synthetic static R_ADDR relocs must be skipped
   298				// now, or else we will be caught in an infinite loop
   299				// of generating synthetic relocs for our synthetic
   300				// relocs.
   301				//
   302				// Furthermore, the rela sections contain dynamic
   303				// relocations with R_ADDR relocations on
   304				// Elf64_Rela.r_offset. This field should contain the
   305				// symbol offset as determined by reloc(), not the
   306				// final dynamically linked address as a dynamic
   307				// relocation would provide.
   308				switch s.Name {
   309				case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
   310					return false
   311				}
   312			} else {
   313				// Either internally linking a static executable,
   314				// in which case we can resolve these relocations
   315				// statically in the 'reloc' phase, or externally
   316				// linking, in which case the relocation will be
   317				// prepared in the 'reloc' phase and passed to the
   318				// external linker in the 'asmb' phase.
   319				if s.Type != sym.SDATA && s.Type != sym.SRODATA {
   320					break
   321				}
   322			}
   323	
   324			if ctxt.IsELF {
   325				// TODO: We generate a R_X86_64_64 relocation for every R_ADDR, even
   326				// though it would be more efficient (for the dynamic linker) if we
   327				// generated R_X86_RELATIVE instead.
   328				ld.Adddynsym(ctxt, targ)
   329				rela := ctxt.Syms.Lookup(".rela", 0)
   330				rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
   331				if r.Siz == 8 {
   332					rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_64)))
   333				} else {
   334					// TODO: never happens, remove.
   335					rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_X86_64_32)))
   336				}
   337				rela.AddUint64(ctxt.Arch, uint64(r.Add))
   338				r.Type = objabi.ElfRelocOffset // ignore during relocsym
   339				return true
   340			}
   341	
   342			if ctxt.HeadType == objabi.Hdarwin && s.Size == int64(ctxt.Arch.PtrSize) && r.Off == 0 {
   343				// Mach-O relocations are a royal pain to lay out.
   344				// They use a compact stateful bytecode representation
   345				// that is too much bother to deal with.
   346				// Instead, interpret the C declaration
   347				//	void *_Cvar_stderr = &stderr;
   348				// as making _Cvar_stderr the name of a GOT entry
   349				// for stderr. This is separate from the usual GOT entry,
   350				// just in case the C code assigns to the variable,
   351				// and of course it only works for single pointers,
   352				// but we only need to support cgo and that's all it needs.
   353				ld.Adddynsym(ctxt, targ)
   354	
   355				got := ctxt.Syms.Lookup(".got", 0)
   356				s.Type = got.Type
   357				s.Attr |= sym.AttrSubSymbol
   358				s.Outer = got
   359				s.Sub = got.Sub
   360				got.Sub = s
   361				s.Value = got.Size
   362				got.AddUint64(ctxt.Arch, 0)
   363				ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(targ.Dynid))
   364				r.Type = objabi.ElfRelocOffset // ignore during relocsym
   365				return true
   366			}
   367		}
   368	
   369		return false
   370	}
   371	
   372	func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   373		ctxt.Out.Write64(uint64(sectoff))
   374	
   375		elfsym := r.Xsym.ElfsymForReloc()
   376		switch r.Type {
   377		default:
   378			return false
   379		case objabi.R_ADDR:
   380			if r.Siz == 4 {
   381				ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
   382			} else if r.Siz == 8 {
   383				ctxt.Out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
   384			} else {
   385				return false
   386			}
   387		case objabi.R_TLS_LE:
   388			if r.Siz == 4 {
   389				ctxt.Out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
   390			} else {
   391				return false
   392			}
   393		case objabi.R_TLS_IE:
   394			if r.Siz == 4 {
   395				ctxt.Out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
   396			} else {
   397				return false
   398			}
   399		case objabi.R_CALL:
   400			if r.Siz == 4 {
   401				if r.Xsym.Type == sym.SDYNIMPORT {
   402					if ctxt.DynlinkingGo() {
   403						ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
   404					} else {
   405						ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
   406					}
   407				} else {
   408					ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
   409				}
   410			} else {
   411				return false
   412			}
   413		case objabi.R_PCREL:
   414			if r.Siz == 4 {
   415				if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType() == elf.STT_FUNC {
   416					ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
   417				} else {
   418					ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
   419				}
   420			} else {
   421				return false
   422			}
   423		case objabi.R_GOTPCREL:
   424			if r.Siz == 4 {
   425				ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
   426			} else {
   427				return false
   428			}
   429		}
   430	
   431		ctxt.Out.Write64(uint64(r.Xadd))
   432		return true
   433	}
   434	
   435	func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   436		var v uint32
   437	
   438		rs := r.Xsym
   439	
   440		if rs.Type == sym.SHOSTOBJ || r.Type == objabi.R_PCREL || r.Type == objabi.R_GOTPCREL || r.Type == objabi.R_CALL {
   441			if rs.Dynid < 0 {
   442				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)
   443				return false
   444			}
   445	
   446			v = uint32(rs.Dynid)
   447			v |= 1 << 27 // external relocation
   448		} else {
   449			v = uint32(rs.Sect.Extnum)
   450			if v == 0 {
   451				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)
   452				return false
   453			}
   454		}
   455	
   456		switch r.Type {
   457		default:
   458			return false
   459	
   460		case objabi.R_ADDR:
   461			v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
   462	
   463		case objabi.R_CALL:
   464			v |= 1 << 24 // pc-relative bit
   465			v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
   466	
   467			// NOTE: Only works with 'external' relocation. Forced above.
   468		case objabi.R_PCREL:
   469			v |= 1 << 24 // pc-relative bit
   470			v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
   471		case objabi.R_GOTPCREL:
   472			v |= 1 << 24 // pc-relative bit
   473			v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
   474		}
   475	
   476		switch r.Siz {
   477		default:
   478			return false
   479	
   480		case 1:
   481			v |= 0 << 25
   482	
   483		case 2:
   484			v |= 1 << 25
   485	
   486		case 4:
   487			v |= 2 << 25
   488	
   489		case 8:
   490			v |= 3 << 25
   491		}
   492	
   493		out.Write32(uint32(sectoff))
   494		out.Write32(v)
   495		return true
   496	}
   497	
   498	func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   499		var v uint32
   500	
   501		rs := r.Xsym
   502	
   503		if rs.Dynid < 0 {
   504			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)
   505			return false
   506		}
   507	
   508		out.Write32(uint32(sectoff))
   509		out.Write32(uint32(rs.Dynid))
   510	
   511		switch r.Type {
   512		default:
   513			return false
   514	
   515		case objabi.R_DWARFSECREF:
   516			v = ld.IMAGE_REL_AMD64_SECREL
   517	
   518		case objabi.R_ADDR:
   519			if r.Siz == 8 {
   520				v = ld.IMAGE_REL_AMD64_ADDR64
   521			} else {
   522				v = ld.IMAGE_REL_AMD64_ADDR32
   523			}
   524	
   525		case objabi.R_CALL,
   526			objabi.R_PCREL:
   527			v = ld.IMAGE_REL_AMD64_REL32
   528		}
   529	
   530		out.Write16(uint16(v))
   531	
   532		return true
   533	}
   534	
   535	func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
   536		return val, false
   537	}
   538	
   539	func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   540		log.Fatalf("unexpected relocation variant")
   541		return t
   542	}
   543	
   544	func elfsetupplt(ctxt *ld.Link) {
   545		plt := ctxt.Syms.Lookup(".plt", 0)
   546		got := ctxt.Syms.Lookup(".got.plt", 0)
   547		if plt.Size == 0 {
   548			// pushq got+8(IP)
   549			plt.AddUint8(0xff)
   550	
   551			plt.AddUint8(0x35)
   552			plt.AddPCRelPlus(ctxt.Arch, got, 8)
   553	
   554			// jmpq got+16(IP)
   555			plt.AddUint8(0xff)
   556	
   557			plt.AddUint8(0x25)
   558			plt.AddPCRelPlus(ctxt.Arch, got, 16)
   559	
   560			// nopl 0(AX)
   561			plt.AddUint32(ctxt.Arch, 0x00401f0f)
   562	
   563			// assume got->size == 0 too
   564			got.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".dynamic", 0), 0)
   565	
   566			got.AddUint64(ctxt.Arch, 0)
   567			got.AddUint64(ctxt.Arch, 0)
   568		}
   569	}
   570	
   571	func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
   572		if s.Plt() >= 0 {
   573			return
   574		}
   575	
   576		ld.Adddynsym(ctxt, s)
   577	
   578		if ctxt.IsELF {
   579			plt := ctxt.Syms.Lookup(".plt", 0)
   580			got := ctxt.Syms.Lookup(".got.plt", 0)
   581			rela := ctxt.Syms.Lookup(".rela.plt", 0)
   582			if plt.Size == 0 {
   583				elfsetupplt(ctxt)
   584			}
   585	
   586			// jmpq *got+size(IP)
   587			plt.AddUint8(0xff)
   588	
   589			plt.AddUint8(0x25)
   590			plt.AddPCRelPlus(ctxt.Arch, got, got.Size)
   591	
   592			// add to got: pointer to current pos in plt
   593			got.AddAddrPlus(ctxt.Arch, plt, plt.Size)
   594	
   595			// pushq $x
   596			plt.AddUint8(0x68)
   597	
   598			plt.AddUint32(ctxt.Arch, uint32((got.Size-24-8)/8))
   599	
   600			// jmpq .plt
   601			plt.AddUint8(0xe9)
   602	
   603			plt.AddUint32(ctxt.Arch, uint32(-(plt.Size + 4)))
   604	
   605			// rela
   606			rela.AddAddrPlus(ctxt.Arch, got, got.Size-8)
   607	
   608			rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT)))
   609			rela.AddUint64(ctxt.Arch, 0)
   610	
   611			s.SetPlt(int32(plt.Size - 16))
   612		} else if ctxt.HeadType == objabi.Hdarwin {
   613			// To do lazy symbol lookup right, we're supposed
   614			// to tell the dynamic loader which library each
   615			// symbol comes from and format the link info
   616			// section just so. I'm too lazy (ha!) to do that
   617			// so for now we'll just use non-lazy pointers,
   618			// which don't need to be told which library to use.
   619			//
   620			// https://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
   621			// has details about what we're avoiding.
   622	
   623			addgotsym(ctxt, s)
   624			plt := ctxt.Syms.Lookup(".plt", 0)
   625	
   626			ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   627	
   628			// jmpq *got+size(IP)
   629			s.SetPlt(int32(plt.Size))
   630	
   631			plt.AddUint8(0xff)
   632			plt.AddUint8(0x25)
   633			plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got()))
   634		} else {
   635			ld.Errorf(s, "addpltsym: unsupported binary format")
   636		}
   637	}
   638	
   639	func addgotsym(ctxt *ld.Link, s *sym.Symbol) {
   640		if s.Got() >= 0 {
   641			return
   642		}
   643	
   644		ld.Adddynsym(ctxt, s)
   645		got := ctxt.Syms.Lookup(".got", 0)
   646		s.SetGot(int32(got.Size))
   647		got.AddUint64(ctxt.Arch, 0)
   648	
   649		if ctxt.IsELF {
   650			rela := ctxt.Syms.Lookup(".rela", 0)
   651			rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got()))
   652			rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT)))
   653			rela.AddUint64(ctxt.Arch, 0)
   654		} else if ctxt.HeadType == objabi.Hdarwin {
   655			ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid))
   656		} else {
   657			ld.Errorf(s, "addgotsym: unsupported binary format")
   658		}
   659	}
   660	
   661	func asmb(ctxt *ld.Link) {
   662		if ctxt.Debugvlog != 0 {
   663			ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   664		}
   665	
   666		if ctxt.Debugvlog != 0 {
   667			ctxt.Logf("%5.2f codeblk\n", ld.Cputime())
   668		}
   669	
   670		if ctxt.IsELF {
   671			ld.Asmbelfsetup()
   672		}
   673	
   674		sect := ld.Segtext.Sections[0]
   675		ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   676		// 0xCC is INT $3 - breakpoint instruction
   677		ld.CodeblkPad(ctxt, int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
   678		for _, sect = range ld.Segtext.Sections[1:] {
   679			ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   680			ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   681		}
   682	
   683		if ld.Segrodata.Filelen > 0 {
   684			if ctxt.Debugvlog != 0 {
   685				ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   686			}
   687			ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
   688			ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   689		}
   690		if ld.Segrelrodata.Filelen > 0 {
   691			if ctxt.Debugvlog != 0 {
   692				ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   693			}
   694			ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
   695			ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   696		}
   697	
   698		if ctxt.Debugvlog != 0 {
   699			ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   700		}
   701	
   702		ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   703		ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   704	
   705		ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
   706		ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   707	}
   708	
   709	func asmb2(ctxt *ld.Link) {
   710		machlink := int64(0)
   711		if ctxt.HeadType == objabi.Hdarwin {
   712			machlink = ld.Domacholink(ctxt)
   713		}
   714	
   715		switch ctxt.HeadType {
   716		default:
   717			ld.Errorf(nil, "unknown header type %v", ctxt.HeadType)
   718			fallthrough
   719	
   720		case objabi.Hplan9:
   721			break
   722	
   723		case objabi.Hdarwin:
   724			ld.Flag8 = true /* 64-bit addresses */
   725	
   726		case objabi.Hlinux,
   727			objabi.Hfreebsd,
   728			objabi.Hnetbsd,
   729			objabi.Hopenbsd,
   730			objabi.Hdragonfly,
   731			objabi.Hsolaris:
   732			ld.Flag8 = true /* 64-bit addresses */
   733	
   734		case objabi.Hnacl,
   735			objabi.Hwindows:
   736			break
   737		}
   738	
   739		ld.Symsize = 0
   740		ld.Spsize = 0
   741		ld.Lcsize = 0
   742		symo := int64(0)
   743		if !*ld.FlagS {
   744			if ctxt.Debugvlog != 0 {
   745				ctxt.Logf("%5.2f sym\n", ld.Cputime())
   746			}
   747			switch ctxt.HeadType {
   748			default:
   749			case objabi.Hplan9:
   750				*ld.FlagS = true
   751				symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   752	
   753			case objabi.Hdarwin:
   754				symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
   755	
   756			case objabi.Hlinux,
   757				objabi.Hfreebsd,
   758				objabi.Hnetbsd,
   759				objabi.Hopenbsd,
   760				objabi.Hdragonfly,
   761				objabi.Hsolaris,
   762				objabi.Hnacl:
   763				symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   764				symo = ld.Rnd(symo, int64(*ld.FlagRound))
   765	
   766			case objabi.Hwindows:
   767				symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   768				symo = ld.Rnd(symo, ld.PEFILEALIGN)
   769			}
   770	
   771			ctxt.Out.SeekSet(symo)
   772			switch ctxt.HeadType {
   773			default:
   774				if ctxt.IsELF {
   775					ctxt.Out.SeekSet(symo)
   776					ld.Asmelfsym(ctxt)
   777					ctxt.Out.Flush()
   778					ctxt.Out.Write(ld.Elfstrdat)
   779	
   780					if ctxt.Debugvlog != 0 {
   781						ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
   782					}
   783	
   784					if ctxt.LinkMode == ld.LinkExternal {
   785						ld.Elfemitreloc(ctxt)
   786					}
   787				}
   788	
   789			case objabi.Hplan9:
   790				ld.Asmplan9sym(ctxt)
   791				ctxt.Out.Flush()
   792	
   793				sym := ctxt.Syms.Lookup("pclntab", 0)
   794				if sym != nil {
   795					ld.Lcsize = int32(len(sym.P))
   796					ctxt.Out.Write(sym.P)
   797					ctxt.Out.Flush()
   798				}
   799	
   800			case objabi.Hwindows:
   801				if ctxt.Debugvlog != 0 {
   802					ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
   803				}
   804	
   805			case objabi.Hdarwin:
   806				if ctxt.LinkMode == ld.LinkExternal {
   807					ld.Machoemitreloc(ctxt)
   808				}
   809			}
   810		}
   811	
   812		if ctxt.Debugvlog != 0 {
   813			ctxt.Logf("%5.2f headr\n", ld.Cputime())
   814		}
   815		ctxt.Out.SeekSet(0)
   816		switch ctxt.HeadType {
   817		default:
   818		case objabi.Hplan9: /* plan9 */
   819			magic := int32(4*26*26 + 7)
   820	
   821			magic |= 0x00008000                           /* fat header */
   822			ctxt.Out.Write32b(uint32(magic))              /* magic */
   823			ctxt.Out.Write32b(uint32(ld.Segtext.Filelen)) /* sizes */
   824			ctxt.Out.Write32b(uint32(ld.Segdata.Filelen))
   825			ctxt.Out.Write32b(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   826			ctxt.Out.Write32b(uint32(ld.Symsize)) /* nsyms */
   827			vl := ld.Entryvalue(ctxt)
   828			ctxt.Out.Write32b(PADDR(uint32(vl))) /* va of entry */
   829			ctxt.Out.Write32b(uint32(ld.Spsize)) /* sp offsets */
   830			ctxt.Out.Write32b(uint32(ld.Lcsize)) /* line offsets */
   831			ctxt.Out.Write64b(uint64(vl))        /* va of entry */
   832	
   833		case objabi.Hdarwin:
   834			ld.Asmbmacho(ctxt)
   835	
   836		case objabi.Hlinux,
   837			objabi.Hfreebsd,
   838			objabi.Hnetbsd,
   839			objabi.Hopenbsd,
   840			objabi.Hdragonfly,
   841			objabi.Hsolaris,
   842			objabi.Hnacl:
   843			ld.Asmbelf(ctxt, symo)
   844	
   845		case objabi.Hwindows:
   846			ld.Asmbpe(ctxt)
   847		}
   848	
   849		ctxt.Out.Flush()
   850	}
   851	
   852	func tlsIEtoLE(s *sym.Symbol, off, size int) {
   853		// Transform the PC-relative instruction into a constant load.
   854		// That is,
   855		//
   856		//	MOVQ X(IP), REG  ->  MOVQ $Y, REG
   857		//
   858		// To determine the instruction and register, we study the op codes.
   859		// Consult an AMD64 instruction encoding guide to decipher this.
   860		if off < 3 {
   861			log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
   862		}
   863		op := s.P[off-3 : off]
   864		reg := op[2] >> 3
   865	
   866		if op[1] == 0x8b || reg == 4 {
   867			// MOVQ
   868			if op[0] == 0x4c {
   869				op[0] = 0x49
   870			} else if size == 4 && op[0] == 0x44 {
   871				op[0] = 0x41
   872			}
   873			if op[1] == 0x8b {
   874				op[1] = 0xc7
   875			} else {
   876				op[1] = 0x81 // special case for SP
   877			}
   878			op[2] = 0xc0 | reg
   879		} else {
   880			// An alternate op is ADDQ. This is handled by GNU gold,
   881			// but right now is not generated by the Go compiler:
   882			//	ADDQ X(IP), REG  ->  ADDQ $Y, REG
   883			// Consider adding support for it here.
   884			log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
   885		}
   886	}
   887	

View as plain text