Home | History | Annotate | Download | only in amd64
      1 // Do not edit. Bootstrap copy of /usr/local/google/buildbot/src/android/build-tools/out/obj/go/src/cmd/link/internal/amd64/asm.go
      2 
      3 //line /usr/local/google/buildbot/src/android/build-tools/out/obj/go/src/cmd/link/internal/amd64/asm.go:1
      4 // Inferno utils/6l/asm.c
      5 // http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
      6 //
      7 //	Copyright  1994-1999 Lucent Technologies Inc.  All rights reserved.
      8 //	Portions Copyright  1995-1997 C H Forsyth (forsyth (a] terzarima.net)
      9 //	Portions Copyright  1997-1999 Vita Nuova Limited
     10 //	Portions Copyright  2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     11 //	Portions Copyright  2004,2006 Bruce Ellis
     12 //	Portions Copyright  2005-2007 C H Forsyth (forsyth (a] terzarima.net)
     13 //	Revisions Copyright  2000-2007 Lucent Technologies Inc. and others
     14 //	Portions Copyright  2009 The Go Authors.  All rights reserved.
     15 //
     16 // Permission is hereby granted, free of charge, to any person obtaining a copy
     17 // of this software and associated documentation files (the "Software"), to deal
     18 // in the Software without restriction, including without limitation the rights
     19 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     20 // copies of the Software, and to permit persons to whom the Software is
     21 // furnished to do so, subject to the following conditions:
     22 //
     23 // The above copyright notice and this permission notice shall be included in
     24 // all copies or substantial portions of the Software.
     25 //
     26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     27 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     28 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     29 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     30 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     31 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     32 // THE SOFTWARE.
     33 
     34 package amd64
     35 
     36 import (
     37 	"bootstrap/internal/obj"
     38 	"bootstrap/link/internal/ld"
     39 	"debug/elf"
     40 	"fmt"
     41 	"log"
     42 )
     43 
     44 func PADDR(x uint32) uint32 {
     45 	return x &^ 0x80000000
     46 }
     47 
     48 var zeroes string
     49 
     50 func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
     51 	s.Reachable = true
     52 	i := s.Size
     53 	s.Size += 4
     54 	ld.Symgrow(ctxt, s, s.Size)
     55 	r := ld.Addrel(s)
     56 	r.Sym = t
     57 	r.Off = int32(i)
     58 	r.Type = obj.R_CALL
     59 	r.Siz = 4
     60 	return i + int64(r.Siz)
     61 }
     62 
     63 func gentext() {
     64 	if !ld.DynlinkingGo() {
     65 		return
     66 	}
     67 	addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
     68 	if addmoduledata.Type == obj.STEXT {
     69 		// we're linking a module containing the runtime -> no need for
     70 		// an init function
     71 		return
     72 	}
     73 	addmoduledata.Reachable = true
     74 	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
     75 	initfunc.Type = obj.STEXT
     76 	initfunc.Local = true
     77 	initfunc.Reachable = true
     78 	o := func(op ...uint8) {
     79 		for _, op1 := range op {
     80 			ld.Adduint8(ld.Ctxt, initfunc, op1)
     81 		}
     82 	}
     83 	// 0000000000000000 <local.dso_init>:
     84 	//    0:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 7 <local.dso_init+0x7>
     85 	// 			3: R_X86_64_PC32	runtime.firstmoduledata-0x4
     86 	o(0x48, 0x8d, 0x3d)
     87 	ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "runtime.firstmoduledata", 0), 0)
     88 	//    7:	e8 00 00 00 00       	callq  c <local.dso_init+0xc>
     89 	// 			8: R_X86_64_PLT32	runtime.addmoduledata-0x4
     90 	o(0xe8)
     91 	Addcall(ld.Ctxt, initfunc, addmoduledata)
     92 	//    c:	c3                   	retq
     93 	o(0xc3)
     94 	if ld.Ctxt.Etextp != nil {
     95 		ld.Ctxt.Etextp.Next = initfunc
     96 	} else {
     97 		ld.Ctxt.Textp = initfunc
     98 	}
     99 	ld.Ctxt.Etextp = initfunc
    100 	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
    101 	initarray_entry.Reachable = true
    102 	initarray_entry.Local = true
    103 	initarray_entry.Type = obj.SINITARR
    104 	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
    105 }
    106 
    107 func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
    108 	ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
    109 	ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
    110 	ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
    111 }
    112 
    113 func adddynrel(s *ld.LSym, r *ld.Reloc) {
    114 	targ := r.Sym
    115 	ld.Ctxt.Cursym = s
    116 
    117 	switch r.Type {
    118 	default:
    119 		if r.Type >= 256 {
    120 			ld.Diag("unexpected relocation type %d", r.Type)
    121 			return
    122 		}
    123 
    124 		// Handle relocations found in ELF object files.
    125 	case 256 + ld.R_X86_64_PC32:
    126 		if targ.Type == obj.SDYNIMPORT {
    127 			ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
    128 		}
    129 		if targ.Type == 0 || targ.Type == obj.SXREF {
    130 			ld.Diag("unknown symbol %s in pcrel", targ.Name)
    131 		}
    132 		r.Type = obj.R_PCREL
    133 		r.Add += 4
    134 		return
    135 
    136 	case 256 + ld.R_X86_64_PLT32:
    137 		r.Type = obj.R_PCREL
    138 		r.Add += 4
    139 		if targ.Type == obj.SDYNIMPORT {
    140 			addpltsym(targ)
    141 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    142 			r.Add += int64(targ.Plt)
    143 		}
    144 
    145 		return
    146 
    147 	case 256 + ld.R_X86_64_GOTPCREL:
    148 		if targ.Type != obj.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 = obj.R_PCREL
    155 				r.Add += 4
    156 				return
    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(targ)
    163 
    164 		r.Type = obj.R_PCREL
    165 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    166 		r.Add += 4
    167 		r.Add += int64(targ.Got)
    168 		return
    169 
    170 	case 256 + ld.R_X86_64_64:
    171 		if targ.Type == obj.SDYNIMPORT {
    172 			ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
    173 		}
    174 		r.Type = obj.R_ADDR
    175 		return
    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 = obj.R_ADDR
    183 
    184 		if targ.Type == obj.SDYNIMPORT {
    185 			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
    186 		}
    187 		return
    188 
    189 	case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
    190 		if targ.Type == obj.SDYNIMPORT {
    191 			addpltsym(targ)
    192 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    193 			r.Add = int64(targ.Plt)
    194 			r.Type = obj.R_PCREL
    195 			return
    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 = obj.R_PCREL
    206 
    207 		if targ.Type == obj.SDYNIMPORT {
    208 			ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
    209 		}
    210 		return
    211 
    212 	case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
    213 		if targ.Type != obj.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.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
    218 				return
    219 			}
    220 
    221 			s.P[r.Off-2] = 0x8d
    222 			r.Type = obj.R_PCREL
    223 			return
    224 		}
    225 		fallthrough
    226 
    227 		// fall through
    228 	case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
    229 		if targ.Type != obj.SDYNIMPORT {
    230 			ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
    231 		}
    232 		addgotsym(targ)
    233 		r.Type = obj.R_PCREL
    234 		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    235 		r.Add += int64(targ.Got)
    236 		return
    237 	}
    238 
    239 	// Handle references to ELF symbols from our own object files.
    240 	if targ.Type != obj.SDYNIMPORT {
    241 		return
    242 	}
    243 
    244 	switch r.Type {
    245 	case obj.R_CALL,
    246 		obj.R_PCREL:
    247 		if ld.HEADTYPE == obj.Hwindows {
    248 			// nothing to do, the relocation will be laid out in pereloc1
    249 			return
    250 		} else {
    251 			// for both ELF and Mach-O
    252 			addpltsym(targ)
    253 			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    254 			r.Add = int64(targ.Plt)
    255 			return
    256 		}
    257 
    258 	case obj.R_ADDR:
    259 		if s.Type == obj.STEXT && ld.Iself {
    260 			if ld.HEADTYPE == obj.Hsolaris {
    261 				addpltsym(targ)
    262 				r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
    263 				r.Add += int64(targ.Plt)
    264 				return
    265 			}
    266 			// The code is asking for the address of an external
    267 			// function.  We provide it with the address of the
    268 			// correspondent GOT symbol.
    269 			addgotsym(targ)
    270 
    271 			r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
    272 			r.Add += int64(targ.Got)
    273 			return
    274 		}
    275 
    276 		if s.Type != obj.SDATA {
    277 			break
    278 		}
    279 		if ld.Iself {
    280 			ld.Adddynsym(ld.Ctxt, targ)
    281 			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
    282 			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
    283 			if r.Siz == 8 {
    284 				ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
    285 			} else {
    286 				ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
    287 			}
    288 			ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
    289 			r.Type = 256 // ignore during relocsym
    290 			return
    291 		}
    292 
    293 		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
    294 			// Mach-O relocations are a royal pain to lay out.
    295 			// They use a compact stateful bytecode representation
    296 			// that is too much bother to deal with.
    297 			// Instead, interpret the C declaration
    298 			//	void *_Cvar_stderr = &stderr;
    299 			// as making _Cvar_stderr the name of a GOT entry
    300 			// for stderr.  This is separate from the usual GOT entry,
    301 			// just in case the C code assigns to the variable,
    302 			// and of course it only works for single pointers,
    303 			// but we only need to support cgo and that's all it needs.
    304 			ld.Adddynsym(ld.Ctxt, targ)
    305 
    306 			got := ld.Linklookup(ld.Ctxt, ".got", 0)
    307 			s.Type = got.Type | obj.SSUB
    308 			s.Outer = got
    309 			s.Sub = got.Sub
    310 			got.Sub = s
    311 			s.Value = got.Size
    312 			ld.Adduint64(ld.Ctxt, got, 0)
    313 			ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
    314 			r.Type = 256 // ignore during relocsym
    315 			return
    316 		}
    317 
    318 		if ld.HEADTYPE == obj.Hwindows {
    319 			// nothing to do, the relocation will be laid out in pereloc1
    320 			return
    321 		}
    322 	}
    323 
    324 	ld.Ctxt.Cursym = s
    325 	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
    326 }
    327 
    328 func elfreloc1(r *ld.Reloc, sectoff int64) int {
    329 	ld.Thearch.Vput(uint64(sectoff))
    330 
    331 	elfsym := r.Xsym.Elfsym
    332 	switch r.Type {
    333 	default:
    334 		return -1
    335 
    336 	case obj.R_ADDR:
    337 		if r.Siz == 4 {
    338 			ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
    339 		} else if r.Siz == 8 {
    340 			ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32)
    341 		} else {
    342 			return -1
    343 		}
    344 
    345 	case obj.R_TLS_LE:
    346 		if r.Siz == 4 {
    347 			ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
    348 		} else {
    349 			return -1
    350 		}
    351 
    352 	case obj.R_TLS_IE:
    353 		if r.Siz == 4 {
    354 			ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
    355 		} else {
    356 			return -1
    357 		}
    358 
    359 	case obj.R_CALL:
    360 		if r.Siz == 4 {
    361 			if r.Xsym.Type == obj.SDYNIMPORT {
    362 				if ld.DynlinkingGo() {
    363 					ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
    364 				} else {
    365 					ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
    366 				}
    367 			} else {
    368 				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
    369 			}
    370 		} else {
    371 			return -1
    372 		}
    373 
    374 	case obj.R_PCREL:
    375 		if r.Siz == 4 {
    376 			if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
    377 				ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
    378 			} else {
    379 				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
    380 			}
    381 		} else {
    382 			return -1
    383 		}
    384 
    385 	case obj.R_GOTPCREL:
    386 		if r.Siz == 4 {
    387 			ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
    388 		} else {
    389 			return -1
    390 		}
    391 	}
    392 
    393 	ld.Thearch.Vput(uint64(r.Xadd))
    394 	return 0
    395 }
    396 
    397 func machoreloc1(r *ld.Reloc, sectoff int64) int {
    398 	var v uint32
    399 
    400 	rs := r.Xsym
    401 
    402 	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL {
    403 		if rs.Dynid < 0 {
    404 			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
    405 			return -1
    406 		}
    407 
    408 		v = uint32(rs.Dynid)
    409 		v |= 1 << 27 // external relocation
    410 	} else {
    411 		v = uint32(rs.Sect.Extnum)
    412 		if v == 0 {
    413 			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
    414 			return -1
    415 		}
    416 	}
    417 
    418 	switch r.Type {
    419 	default:
    420 		return -1
    421 
    422 	case obj.R_ADDR:
    423 		v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
    424 
    425 	case obj.R_CALL:
    426 		v |= 1 << 24 // pc-relative bit
    427 		v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
    428 
    429 		// NOTE: Only works with 'external' relocation. Forced above.
    430 	case obj.R_PCREL:
    431 		v |= 1 << 24 // pc-relative bit
    432 		v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
    433 	}
    434 
    435 	switch r.Siz {
    436 	default:
    437 		return -1
    438 
    439 	case 1:
    440 		v |= 0 << 25
    441 
    442 	case 2:
    443 		v |= 1 << 25
    444 
    445 	case 4:
    446 		v |= 2 << 25
    447 
    448 	case 8:
    449 		v |= 3 << 25
    450 	}
    451 
    452 	ld.Thearch.Lput(uint32(sectoff))
    453 	ld.Thearch.Lput(v)
    454 	return 0
    455 }
    456 
    457 func pereloc1(r *ld.Reloc, sectoff int64) bool {
    458 	var v uint32
    459 
    460 	rs := r.Xsym
    461 
    462 	if rs.Dynid < 0 {
    463 		ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
    464 		return false
    465 	}
    466 
    467 	ld.Thearch.Lput(uint32(sectoff))
    468 	ld.Thearch.Lput(uint32(rs.Dynid))
    469 
    470 	switch r.Type {
    471 	default:
    472 		return false
    473 
    474 	case obj.R_ADDR:
    475 		if r.Siz == 8 {
    476 			v = ld.IMAGE_REL_AMD64_ADDR64
    477 		} else {
    478 			v = ld.IMAGE_REL_AMD64_ADDR32
    479 		}
    480 
    481 	case obj.R_CALL,
    482 		obj.R_PCREL:
    483 		v = ld.IMAGE_REL_AMD64_REL32
    484 	}
    485 
    486 	ld.Thearch.Wput(uint16(v))
    487 
    488 	return true
    489 }
    490 
    491 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
    492 	return -1
    493 }
    494 
    495 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
    496 	log.Fatalf("unexpected relocation variant")
    497 	return t
    498 }
    499 
    500 func elfsetupplt() {
    501 	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
    502 	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
    503 	if plt.Size == 0 {
    504 		// pushq got+8(IP)
    505 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    506 
    507 		ld.Adduint8(ld.Ctxt, plt, 0x35)
    508 		ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
    509 
    510 		// jmpq got+16(IP)
    511 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    512 
    513 		ld.Adduint8(ld.Ctxt, plt, 0x25)
    514 		ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
    515 
    516 		// nopl 0(AX)
    517 		ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
    518 
    519 		// assume got->size == 0 too
    520 		ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
    521 
    522 		ld.Adduint64(ld.Ctxt, got, 0)
    523 		ld.Adduint64(ld.Ctxt, got, 0)
    524 	}
    525 }
    526 
    527 func addpltsym(s *ld.LSym) {
    528 	if s.Plt >= 0 {
    529 		return
    530 	}
    531 
    532 	ld.Adddynsym(ld.Ctxt, s)
    533 
    534 	if ld.Iself {
    535 		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
    536 		got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
    537 		rela := ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
    538 		if plt.Size == 0 {
    539 			elfsetupplt()
    540 		}
    541 
    542 		// jmpq *got+size(IP)
    543 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    544 
    545 		ld.Adduint8(ld.Ctxt, plt, 0x25)
    546 		ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
    547 
    548 		// add to got: pointer to current pos in plt
    549 		ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
    550 
    551 		// pushq $x
    552 		ld.Adduint8(ld.Ctxt, plt, 0x68)
    553 
    554 		ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
    555 
    556 		// jmpq .plt
    557 		ld.Adduint8(ld.Ctxt, plt, 0xe9)
    558 
    559 		ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
    560 
    561 		// rela
    562 		ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
    563 
    564 		ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
    565 		ld.Adduint64(ld.Ctxt, rela, 0)
    566 
    567 		s.Plt = int32(plt.Size - 16)
    568 	} else if ld.HEADTYPE == obj.Hdarwin {
    569 		// To do lazy symbol lookup right, we're supposed
    570 		// to tell the dynamic loader which library each
    571 		// symbol comes from and format the link info
    572 		// section just so.  I'm too lazy (ha!) to do that
    573 		// so for now we'll just use non-lazy pointers,
    574 		// which don't need to be told which library to use.
    575 		//
    576 		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
    577 		// has details about what we're avoiding.
    578 
    579 		addgotsym(s)
    580 		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
    581 
    582 		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
    583 
    584 		// jmpq *got+size(IP)
    585 		s.Plt = int32(plt.Size)
    586 
    587 		ld.Adduint8(ld.Ctxt, plt, 0xff)
    588 		ld.Adduint8(ld.Ctxt, plt, 0x25)
    589 		ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
    590 	} else {
    591 		ld.Diag("addpltsym: unsupported binary format")
    592 	}
    593 }
    594 
    595 func addgotsym(s *ld.LSym) {
    596 	if s.Got >= 0 {
    597 		return
    598 	}
    599 
    600 	ld.Adddynsym(ld.Ctxt, s)
    601 	got := ld.Linklookup(ld.Ctxt, ".got", 0)
    602 	s.Got = int32(got.Size)
    603 	ld.Adduint64(ld.Ctxt, got, 0)
    604 
    605 	if ld.Iself {
    606 		rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
    607 		ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
    608 		ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
    609 		ld.Adduint64(ld.Ctxt, rela, 0)
    610 	} else if ld.HEADTYPE == obj.Hdarwin {
    611 		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
    612 	} else {
    613 		ld.Diag("addgotsym: unsupported binary format")
    614 	}
    615 }
    616 
    617 func asmb() {
    618 	if ld.Debug['v'] != 0 {
    619 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
    620 	}
    621 	ld.Bso.Flush()
    622 
    623 	if ld.Debug['v'] != 0 {
    624 		fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
    625 	}
    626 	ld.Bso.Flush()
    627 
    628 	if ld.Iself {
    629 		ld.Asmbelfsetup()
    630 	}
    631 
    632 	sect := ld.Segtext.Sect
    633 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    634 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
    635 	for sect = sect.Next; sect != nil; sect = sect.Next {
    636 		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
    637 		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
    638 	}
    639 
    640 	if ld.Segrodata.Filelen > 0 {
    641 		if ld.Debug['v'] != 0 {
    642 			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
    643 		}
    644 		ld.Bso.Flush()
    645 
    646 		ld.Cseek(int64(ld.Segrodata.Fileoff))
    647 		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
    648 	}
    649 
    650 	if ld.Debug['v'] != 0 {
    651 		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
    652 	}
    653 	ld.Bso.Flush()
    654 
    655 	ld.Cseek(int64(ld.Segdata.Fileoff))
    656 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
    657 
    658 	machlink := int64(0)
    659 	if ld.HEADTYPE == obj.Hdarwin {
    660 		if ld.Debug['v'] != 0 {
    661 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    662 		}
    663 
    664 		dwarfoff := ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
    665 		ld.Cseek(dwarfoff)
    666 
    667 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
    668 		ld.Dwarfemitdebugsections()
    669 		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
    670 
    671 		machlink = ld.Domacholink()
    672 	}
    673 
    674 	switch ld.HEADTYPE {
    675 	default:
    676 		ld.Diag("unknown header type %d", ld.HEADTYPE)
    677 		fallthrough
    678 
    679 	case obj.Hplan9,
    680 		obj.Helf:
    681 		break
    682 
    683 	case obj.Hdarwin:
    684 		ld.Debug['8'] = 1 /* 64-bit addresses */
    685 
    686 	case obj.Hlinux,
    687 		obj.Hfreebsd,
    688 		obj.Hnetbsd,
    689 		obj.Hopenbsd,
    690 		obj.Hdragonfly,
    691 		obj.Hsolaris:
    692 		ld.Debug['8'] = 1 /* 64-bit addresses */
    693 
    694 	case obj.Hnacl,
    695 		obj.Hwindows:
    696 		break
    697 	}
    698 
    699 	ld.Symsize = 0
    700 	ld.Spsize = 0
    701 	ld.Lcsize = 0
    702 	symo := int64(0)
    703 	if ld.Debug['s'] == 0 {
    704 		if ld.Debug['v'] != 0 {
    705 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
    706 		}
    707 		ld.Bso.Flush()
    708 		switch ld.HEADTYPE {
    709 		default:
    710 		case obj.Hplan9,
    711 			obj.Helf:
    712 			ld.Debug['s'] = 1
    713 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    714 
    715 		case obj.Hdarwin:
    716 			symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
    717 
    718 		case obj.Hlinux,
    719 			obj.Hfreebsd,
    720 			obj.Hnetbsd,
    721 			obj.Hopenbsd,
    722 			obj.Hdragonfly,
    723 			obj.Hsolaris,
    724 			obj.Hnacl:
    725 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    726 			symo = ld.Rnd(symo, int64(ld.INITRND))
    727 
    728 		case obj.Hwindows:
    729 			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
    730 			symo = ld.Rnd(symo, ld.PEFILEALIGN)
    731 		}
    732 
    733 		ld.Cseek(symo)
    734 		switch ld.HEADTYPE {
    735 		default:
    736 			if ld.Iself {
    737 				ld.Cseek(symo)
    738 				ld.Asmelfsym()
    739 				ld.Cflush()
    740 				ld.Cwrite(ld.Elfstrdat)
    741 
    742 				if ld.Debug['v'] != 0 {
    743 					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    744 				}
    745 
    746 				ld.Dwarfemitdebugsections()
    747 
    748 				if ld.Linkmode == ld.LinkExternal {
    749 					ld.Elfemitreloc()
    750 				}
    751 			}
    752 
    753 		case obj.Hplan9:
    754 			ld.Asmplan9sym()
    755 			ld.Cflush()
    756 
    757 			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
    758 			if sym != nil {
    759 				ld.Lcsize = int32(len(sym.P))
    760 				for i := 0; int32(i) < ld.Lcsize; i++ {
    761 					ld.Cput(uint8(sym.P[i]))
    762 				}
    763 
    764 				ld.Cflush()
    765 			}
    766 
    767 		case obj.Hwindows:
    768 			if ld.Debug['v'] != 0 {
    769 				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
    770 			}
    771 
    772 			ld.Dwarfemitdebugsections()
    773 
    774 		case obj.Hdarwin:
    775 			if ld.Linkmode == ld.LinkExternal {
    776 				ld.Machoemitreloc()
    777 			}
    778 		}
    779 	}
    780 
    781 	if ld.Debug['v'] != 0 {
    782 		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
    783 	}
    784 	ld.Bso.Flush()
    785 	ld.Cseek(0)
    786 	switch ld.HEADTYPE {
    787 	default:
    788 	case obj.Hplan9: /* plan9 */
    789 		magic := int32(4*26*26 + 7)
    790 
    791 		magic |= 0x00008000                  /* fat header */
    792 		ld.Lputb(uint32(magic))              /* magic */
    793 		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
    794 		ld.Lputb(uint32(ld.Segdata.Filelen))
    795 		ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
    796 		ld.Lputb(uint32(ld.Symsize)) /* nsyms */
    797 		vl := ld.Entryvalue()
    798 		ld.Lputb(PADDR(uint32(vl))) /* va of entry */
    799 		ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
    800 		ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
    801 		ld.Vputb(uint64(vl))        /* va of entry */
    802 
    803 	case obj.Hdarwin:
    804 		ld.Asmbmacho()
    805 
    806 	case obj.Hlinux,
    807 		obj.Hfreebsd,
    808 		obj.Hnetbsd,
    809 		obj.Hopenbsd,
    810 		obj.Hdragonfly,
    811 		obj.Hsolaris,
    812 		obj.Hnacl:
    813 		ld.Asmbelf(symo)
    814 
    815 	case obj.Hwindows:
    816 		ld.Asmbpe()
    817 	}
    818 
    819 	ld.Cflush()
    820 }
    821