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