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