• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Inferno utils/6l/asm.c
2// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/asm.c
3//
4//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6//	Portions Copyright © 1997-1999 Vita Nuova Limited
7//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8//	Portions Copyright © 2004,2006 Bruce Ellis
9//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11//	Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31package amd64
32
33import (
34	"cmd/internal/objabi"
35	"cmd/internal/sys"
36	"cmd/link/internal/ld"
37	"cmd/link/internal/loader"
38	"cmd/link/internal/sym"
39	"debug/elf"
40	"log"
41)
42
43func PADDR(x uint32) uint32 {
44	return x &^ 0x80000000
45}
46
47func gentext(ctxt *ld.Link, ldr *loader.Loader) {
48	initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
49	if initfunc == nil {
50		return
51	}
52
53	o := func(op ...uint8) {
54		for _, op1 := range op {
55			initfunc.AddUint8(op1)
56		}
57	}
58
59	// 0000000000000000 <local.dso_init>:
60	//    0:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 7 <local.dso_init+0x7>
61	// 			3: R_X86_64_PC32	runtime.firstmoduledata-0x4
62	o(0x48, 0x8d, 0x3d)
63	initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 0)
64	//    7:	e8 00 00 00 00       	callq  c <local.dso_init+0xc>
65	// 			8: R_X86_64_PLT32	runtime.addmoduledata-0x4
66	o(0xe8)
67	initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4)
68	//    c:	c3                   	retq
69	o(0xc3)
70}
71
72func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
73	targ := r.Sym()
74	var targType sym.SymKind
75	if targ != 0 {
76		targType = ldr.SymType(targ)
77	}
78
79	switch rt := r.Type(); rt {
80	default:
81		if rt >= objabi.ElfRelocOffset {
82			ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
83			return false
84		}
85
86		// Handle relocations found in ELF object files.
87	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC32):
88		if targType == sym.SDYNIMPORT {
89			ldr.Errorf(s, "unexpected R_X86_64_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
90		}
91		if targType == 0 || targType == sym.SXREF {
92			ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
93		}
94		su := ldr.MakeSymbolUpdater(s)
95		su.SetRelocType(rIdx, objabi.R_PCREL)
96		su.SetRelocAdd(rIdx, r.Add()+4)
97		return true
98
99	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PC64):
100		if targType == sym.SDYNIMPORT {
101			ldr.Errorf(s, "unexpected R_X86_64_PC64 relocation for dynamic symbol %s", ldr.SymName(targ))
102		}
103		if targType == 0 || targType == sym.SXREF {
104			ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
105		}
106		su := ldr.MakeSymbolUpdater(s)
107		su.SetRelocType(rIdx, objabi.R_PCREL)
108		su.SetRelocAdd(rIdx, r.Add()+8)
109		return true
110
111	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_PLT32):
112		su := ldr.MakeSymbolUpdater(s)
113		su.SetRelocType(rIdx, objabi.R_PCREL)
114		su.SetRelocAdd(rIdx, r.Add()+4)
115		if targType == sym.SDYNIMPORT {
116			addpltsym(target, ldr, syms, targ)
117			su.SetRelocSym(rIdx, syms.PLT)
118			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
119		}
120
121		return true
122
123	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCREL),
124		objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_GOTPCRELX),
125		objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_REX_GOTPCRELX):
126		su := ldr.MakeSymbolUpdater(s)
127		if targType != sym.SDYNIMPORT {
128			// have symbol
129			sData := ldr.Data(s)
130			if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
131				su.MakeWritable()
132				// turn MOVQ of GOT entry into LEAQ of symbol itself
133				writeableData := su.Data()
134				writeableData[r.Off()-2] = 0x8d
135				su.SetRelocType(rIdx, objabi.R_PCREL)
136				su.SetRelocAdd(rIdx, r.Add()+4)
137				return true
138			}
139		}
140
141		// fall back to using GOT and hope for the best (CMOV*)
142		// TODO: just needs relocation, no need to put in .dynsym
143		ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
144
145		su.SetRelocType(rIdx, objabi.R_PCREL)
146		su.SetRelocSym(rIdx, syms.GOT)
147		su.SetRelocAdd(rIdx, r.Add()+4+int64(ldr.SymGot(targ)))
148		return true
149
150	case objabi.ElfRelocOffset + objabi.RelocType(elf.R_X86_64_64):
151		if targType == sym.SDYNIMPORT {
152			ldr.Errorf(s, "unexpected R_X86_64_64 relocation for dynamic symbol %s", ldr.SymName(targ))
153		}
154		su := ldr.MakeSymbolUpdater(s)
155		su.SetRelocType(rIdx, objabi.R_ADDR)
156		if target.IsPIE() && target.IsInternal() {
157			// For internal linking PIE, this R_ADDR relocation cannot
158			// be resolved statically. We need to generate a dynamic
159			// relocation. Let the code below handle it.
160			break
161		}
162		return true
163
164	// Handle relocations found in Mach-O object files.
165	case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
166		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
167		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
168		su := ldr.MakeSymbolUpdater(s)
169		su.SetRelocType(rIdx, objabi.R_ADDR)
170
171		if targType == sym.SDYNIMPORT {
172			ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
173		}
174		if target.IsPIE() && target.IsInternal() {
175			// For internal linking PIE, this R_ADDR relocation cannot
176			// be resolved statically. We need to generate a dynamic
177			// relocation. Let the code below handle it.
178			if rt == objabi.MachoRelocOffset+ld.MACHO_X86_64_RELOC_UNSIGNED*2 {
179				break
180			} else {
181				// MACHO_X86_64_RELOC_SIGNED or MACHO_X86_64_RELOC_BRANCH
182				// Can this happen? The object is expected to be PIC.
183				ldr.Errorf(s, "unsupported relocation for PIE: %v", rt)
184			}
185		}
186		return true
187
188	case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
189		if targType == sym.SDYNIMPORT {
190			addpltsym(target, ldr, syms, targ)
191			su := ldr.MakeSymbolUpdater(s)
192			su.SetRelocSym(rIdx, syms.PLT)
193			su.SetRelocType(rIdx, objabi.R_PCREL)
194			su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
195			return true
196		}
197		fallthrough
198
199	case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
200		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
201		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
202		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
203		objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
204		su := ldr.MakeSymbolUpdater(s)
205		su.SetRelocType(rIdx, objabi.R_PCREL)
206
207		if targType == sym.SDYNIMPORT {
208			ldr.Errorf(s, "unexpected pc-relative reloc for dynamic symbol %s", ldr.SymName(targ))
209		}
210		return true
211
212	case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
213		if targType != sym.SDYNIMPORT {
214			// have symbol
215			// turn MOVQ of GOT entry into LEAQ of symbol itself
216			sdata := ldr.Data(s)
217			if r.Off() < 2 || sdata[r.Off()-2] != 0x8b {
218				ldr.Errorf(s, "unexpected GOT_LOAD reloc for non-dynamic symbol %s", ldr.SymName(targ))
219				return false
220			}
221
222			su := ldr.MakeSymbolUpdater(s)
223			su.MakeWritable()
224			sdata = su.Data()
225			sdata[r.Off()-2] = 0x8d
226			su.SetRelocType(rIdx, objabi.R_PCREL)
227			return true
228		}
229		fallthrough
230
231	case objabi.MachoRelocOffset + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
232		if targType != sym.SDYNIMPORT {
233			ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
234		}
235		ld.AddGotSym(target, ldr, syms, targ, 0)
236		su := ldr.MakeSymbolUpdater(s)
237		su.SetRelocType(rIdx, objabi.R_PCREL)
238		su.SetRelocSym(rIdx, syms.GOT)
239		su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
240		return true
241	}
242
243	// Reread the reloc to incorporate any changes in type above.
244	relocs := ldr.Relocs(s)
245	r = relocs.At(rIdx)
246
247	switch r.Type() {
248	case objabi.R_CALL:
249		if targType != sym.SDYNIMPORT {
250			// nothing to do, the relocation will be laid out in reloc
251			return true
252		}
253		if target.IsExternal() {
254			// External linker will do this relocation.
255			return true
256		}
257		// Internal linking, for both ELF and Mach-O.
258		// Build a PLT entry and change the relocation target to that entry.
259		addpltsym(target, ldr, syms, targ)
260		su := ldr.MakeSymbolUpdater(s)
261		su.SetRelocSym(rIdx, syms.PLT)
262		su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
263		return true
264
265	case objabi.R_PCREL:
266		if targType == sym.SDYNIMPORT && ldr.SymType(s) == sym.STEXT && target.IsDarwin() {
267			// Loading the address of a dynamic symbol. Rewrite to use GOT.
268			// turn LEAQ symbol address to MOVQ of GOT entry
269			if r.Add() != 0 {
270				ldr.Errorf(s, "unexpected nonzero addend for dynamic symbol %s", ldr.SymName(targ))
271				return false
272			}
273			su := ldr.MakeSymbolUpdater(s)
274			if r.Off() >= 2 && su.Data()[r.Off()-2] == 0x8d {
275				su.MakeWritable()
276				su.Data()[r.Off()-2] = 0x8b
277				if target.IsInternal() {
278					ld.AddGotSym(target, ldr, syms, targ, 0)
279					su.SetRelocSym(rIdx, syms.GOT)
280					su.SetRelocAdd(rIdx, int64(ldr.SymGot(targ)))
281				} else {
282					su.SetRelocType(rIdx, objabi.R_GOTPCREL)
283				}
284				return true
285			}
286			ldr.Errorf(s, "unexpected R_PCREL reloc for dynamic symbol %s: not preceded by LEAQ instruction", ldr.SymName(targ))
287		}
288
289	case objabi.R_ADDR:
290		if ldr.SymType(s) == sym.STEXT && target.IsElf() {
291			su := ldr.MakeSymbolUpdater(s)
292			if target.IsSolaris() {
293				addpltsym(target, ldr, syms, targ)
294				su.SetRelocSym(rIdx, syms.PLT)
295				su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
296				return true
297			}
298			// The code is asking for the address of an external
299			// function. We provide it with the address of the
300			// correspondent GOT symbol.
301			ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_X86_64_GLOB_DAT))
302
303			su.SetRelocSym(rIdx, syms.GOT)
304			su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
305			return true
306		}
307
308		// Process dynamic relocations for the data sections.
309		if target.IsPIE() && target.IsInternal() {
310			// When internally linking, generate dynamic relocations
311			// for all typical R_ADDR relocations. The exception
312			// are those R_ADDR that are created as part of generating
313			// the dynamic relocations and must be resolved statically.
314			//
315			// There are three phases relevant to understanding this:
316			//
317			//	dodata()  // we are here
318			//	address() // symbol address assignment
319			//	reloc()   // resolution of static R_ADDR relocs
320			//
321			// At this point symbol addresses have not been
322			// assigned yet (as the final size of the .rela section
323			// will affect the addresses), and so we cannot write
324			// the Elf64_Rela.r_offset now. Instead we delay it
325			// until after the 'address' phase of the linker is
326			// complete. We do this via Addaddrplus, which creates
327			// a new R_ADDR relocation which will be resolved in
328			// the 'reloc' phase.
329			//
330			// These synthetic static R_ADDR relocs must be skipped
331			// now, or else we will be caught in an infinite loop
332			// of generating synthetic relocs for our synthetic
333			// relocs.
334			//
335			// Furthermore, the rela sections contain dynamic
336			// relocations with R_ADDR relocations on
337			// Elf64_Rela.r_offset. This field should contain the
338			// symbol offset as determined by reloc(), not the
339			// final dynamically linked address as a dynamic
340			// relocation would provide.
341			switch ldr.SymName(s) {
342			case ".dynsym", ".rela", ".rela.plt", ".got.plt", ".dynamic":
343				return false
344			}
345		} else {
346			// Either internally linking a static executable,
347			// in which case we can resolve these relocations
348			// statically in the 'reloc' phase, or externally
349			// linking, in which case the relocation will be
350			// prepared in the 'reloc' phase and passed to the
351			// external linker in the 'asmb' phase.
352			if ldr.SymType(s) != sym.SDATA && ldr.SymType(s) != sym.SRODATA {
353				break
354			}
355		}
356
357		if target.IsElf() {
358			// Generate R_X86_64_RELATIVE relocations for best
359			// efficiency in the dynamic linker.
360			//
361			// As noted above, symbol addresses have not been
362			// assigned yet, so we can't generate the final reloc
363			// entry yet. We ultimately want:
364			//
365			// r_offset = s + r.Off
366			// r_info = R_X86_64_RELATIVE
367			// r_addend = targ + r.Add
368			//
369			// The dynamic linker will set *offset = base address +
370			// addend.
371			//
372			// AddAddrPlus is used for r_offset and r_addend to
373			// generate new R_ADDR relocations that will update
374			// these fields in the 'reloc' phase.
375			rela := ldr.MakeSymbolUpdater(syms.Rela)
376			rela.AddAddrPlus(target.Arch, s, int64(r.Off()))
377			if r.Siz() == 8 {
378				rela.AddUint64(target.Arch, elf.R_INFO(0, uint32(elf.R_X86_64_RELATIVE)))
379			} else {
380				ldr.Errorf(s, "unexpected relocation for dynamic symbol %s", ldr.SymName(targ))
381			}
382			rela.AddAddrPlus(target.Arch, targ, int64(r.Add()))
383			// Not mark r done here. So we still apply it statically,
384			// so in the file content we'll also have the right offset
385			// to the relocation target. So it can be examined statically
386			// (e.g. go version).
387			return true
388		}
389
390		if target.IsDarwin() {
391			// Mach-O relocations are a royal pain to lay out.
392			// They use a compact stateful bytecode representation.
393			// Here we record what are needed and encode them later.
394			ld.MachoAddRebase(s, int64(r.Off()))
395			// Not mark r done here. So we still apply it statically,
396			// so in the file content we'll also have the right offset
397			// to the relocation target. So it can be examined statically
398			// (e.g. go version).
399			return true
400		}
401	case objabi.R_GOTPCREL:
402		if target.IsExternal() {
403			// External linker will do this relocation.
404			return true
405		}
406		// We only need to handle external linking mode, as R_GOTPCREL can
407		// only occur in plugin or shared build modes.
408	}
409
410	return false
411}
412
413func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
414	out.Write64(uint64(sectoff))
415
416	elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
417	siz := r.Size
418	switch r.Type {
419	default:
420		return false
421	case objabi.R_ADDR, objabi.R_DWARFSECREF:
422		if siz == 4 {
423			out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
424		} else if siz == 8 {
425			out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
426		} else {
427			return false
428		}
429	case objabi.R_TLS_LE:
430		if siz == 4 {
431			out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
432		} else {
433			return false
434		}
435	case objabi.R_TLS_IE:
436		if siz == 4 {
437			out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
438		} else {
439			return false
440		}
441	case objabi.R_CALL:
442		if siz == 4 {
443			if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
444				out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
445			} else {
446				out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
447			}
448		} else {
449			return false
450		}
451	case objabi.R_PCREL:
452		if siz == 4 {
453			if ldr.SymType(r.Xsym) == sym.SDYNIMPORT && ldr.SymElfType(r.Xsym) == elf.STT_FUNC {
454				out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
455			} else {
456				out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
457			}
458		} else {
459			return false
460		}
461	case objabi.R_GOTPCREL:
462		if siz == 4 {
463			out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
464		} else {
465			return false
466		}
467	}
468
469	out.Write64(uint64(r.Xadd))
470	return true
471}
472
473func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
474	var v uint32
475
476	rs := r.Xsym
477	rt := r.Type
478
479	if !ldr.SymType(s).IsDWARF() {
480		if ldr.SymDynid(rs) < 0 {
481			ldr.Errorf(s, "reloc %d (%s) to non-macho symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
482			return false
483		}
484
485		v = uint32(ldr.SymDynid(rs))
486		v |= 1 << 27 // external relocation
487	} else {
488		v = uint32(ldr.SymSect(rs).Extnum)
489		if v == 0 {
490			ldr.Errorf(s, "reloc %d (%s) to symbol %s in non-macho section %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymSect(rs).Name, ldr.SymType(rs), ldr.SymType(rs))
491			return false
492		}
493	}
494
495	switch rt {
496	default:
497		return false
498
499	case objabi.R_ADDR:
500		v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
501
502	case objabi.R_CALL:
503		v |= 1 << 24 // pc-relative bit
504		v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
505
506		// NOTE: Only works with 'external' relocation. Forced above.
507	case objabi.R_PCREL:
508		v |= 1 << 24 // pc-relative bit
509		v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
510	case objabi.R_GOTPCREL:
511		v |= 1 << 24 // pc-relative bit
512		v |= ld.MACHO_X86_64_RELOC_GOT_LOAD << 28
513	}
514
515	switch r.Size {
516	default:
517		return false
518
519	case 1:
520		v |= 0 << 25
521
522	case 2:
523		v |= 1 << 25
524
525	case 4:
526		v |= 2 << 25
527
528	case 8:
529		v |= 3 << 25
530	}
531
532	out.Write32(uint32(sectoff))
533	out.Write32(v)
534	return true
535}
536
537func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
538	var v uint32
539
540	rs := r.Xsym
541	rt := r.Type
542
543	if ldr.SymDynid(rs) < 0 {
544		ldr.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs))
545		return false
546	}
547
548	out.Write32(uint32(sectoff))
549	out.Write32(uint32(ldr.SymDynid(rs)))
550
551	switch rt {
552	default:
553		return false
554
555	case objabi.R_DWARFSECREF:
556		v = ld.IMAGE_REL_AMD64_SECREL
557
558	case objabi.R_ADDR:
559		if r.Size == 8 {
560			v = ld.IMAGE_REL_AMD64_ADDR64
561		} else {
562			v = ld.IMAGE_REL_AMD64_ADDR32
563		}
564
565	case objabi.R_PEIMAGEOFF:
566		v = ld.IMAGE_REL_AMD64_ADDR32NB
567
568	case objabi.R_CALL,
569		objabi.R_PCREL:
570		v = ld.IMAGE_REL_AMD64_REL32
571	}
572
573	out.Write16(uint16(v))
574
575	return true
576}
577
578func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) {
579	return -1, 0, false
580}
581
582func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
583	log.Fatalf("unexpected relocation variant")
584	return -1
585}
586
587func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
588	if plt.Size() == 0 {
589		// pushq got+8(IP)
590		plt.AddUint8(0xff)
591
592		plt.AddUint8(0x35)
593		plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 8)
594
595		// jmpq got+16(IP)
596		plt.AddUint8(0xff)
597
598		plt.AddUint8(0x25)
599		plt.AddPCRelPlus(ctxt.Arch, got.Sym(), 16)
600
601		// nopl 0(AX)
602		plt.AddUint32(ctxt.Arch, 0x00401f0f)
603
604		// assume got->size == 0 too
605		got.AddAddrPlus(ctxt.Arch, dynamic, 0)
606
607		got.AddUint64(ctxt.Arch, 0)
608		got.AddUint64(ctxt.Arch, 0)
609	}
610}
611
612func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
613	if ldr.SymPlt(s) >= 0 {
614		return
615	}
616
617	ld.Adddynsym(ldr, target, syms, s)
618
619	if target.IsElf() {
620		plt := ldr.MakeSymbolUpdater(syms.PLT)
621		got := ldr.MakeSymbolUpdater(syms.GOTPLT)
622		rela := ldr.MakeSymbolUpdater(syms.RelaPLT)
623		if plt.Size() == 0 {
624			panic("plt is not set up")
625		}
626
627		// jmpq *got+size(IP)
628		plt.AddUint8(0xff)
629
630		plt.AddUint8(0x25)
631		plt.AddPCRelPlus(target.Arch, got.Sym(), got.Size())
632
633		// add to got: pointer to current pos in plt
634		got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
635
636		// pushq $x
637		plt.AddUint8(0x68)
638
639		plt.AddUint32(target.Arch, uint32((got.Size()-24-8)/8))
640
641		// jmpq .plt
642		plt.AddUint8(0xe9)
643
644		plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
645
646		// rela
647		rela.AddAddrPlus(target.Arch, got.Sym(), got.Size()-8)
648
649		sDynid := ldr.SymDynid(s)
650		rela.AddUint64(target.Arch, elf.R_INFO(uint32(sDynid), uint32(elf.R_X86_64_JMP_SLOT)))
651		rela.AddUint64(target.Arch, 0)
652
653		ldr.SetPlt(s, int32(plt.Size()-16))
654	} else if target.IsDarwin() {
655		ld.AddGotSym(target, ldr, syms, s, 0)
656
657		sDynid := ldr.SymDynid(s)
658		lep := ldr.MakeSymbolUpdater(syms.LinkEditPLT)
659		lep.AddUint32(target.Arch, uint32(sDynid))
660
661		plt := ldr.MakeSymbolUpdater(syms.PLT)
662		ldr.SetPlt(s, int32(plt.Size()))
663
664		// jmpq *got+size(IP)
665		plt.AddUint8(0xff)
666		plt.AddUint8(0x25)
667		plt.AddPCRelPlus(target.Arch, syms.GOT, int64(ldr.SymGot(s)))
668	} else {
669		ldr.Errorf(s, "addpltsym: unsupported binary format")
670	}
671}
672
673func tlsIEtoLE(P []byte, off, size int) {
674	// Transform the PC-relative instruction into a constant load.
675	// That is,
676	//
677	//	MOVQ X(IP), REG  ->  MOVQ $Y, REG
678	//
679	// To determine the instruction and register, we study the op codes.
680	// Consult an AMD64 instruction encoding guide to decipher this.
681	if off < 3 {
682		log.Fatal("R_X86_64_GOTTPOFF reloc not preceded by MOVQ or ADDQ instruction")
683	}
684	op := P[off-3 : off]
685	reg := op[2] >> 3
686
687	if op[1] == 0x8b || reg == 4 {
688		// MOVQ
689		if op[0] == 0x4c {
690			op[0] = 0x49
691		} else if size == 4 && op[0] == 0x44 {
692			op[0] = 0x41
693		}
694		if op[1] == 0x8b {
695			op[1] = 0xc7
696		} else {
697			op[1] = 0x81 // special case for SP
698		}
699		op[2] = 0xc0 | reg
700	} else {
701		// An alternate op is ADDQ. This is handled by GNU gold,
702		// but right now is not generated by the Go compiler:
703		//	ADDQ X(IP), REG  ->  ADDQ $Y, REG
704		// Consider adding support for it here.
705		log.Fatalf("expected TLS IE op to be MOVQ, got %v", op)
706	}
707}
708