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