1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package x86
32
33 import (
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
43 func gentext(ctxt *ld.Link, ldr *loader.Loader) {
44 if ctxt.DynlinkingGo() {
45
46 } else {
47 switch ctxt.BuildMode {
48 case ld.BuildModeCArchive:
49 if !ctxt.IsELF {
50 return
51 }
52 case ld.BuildModePIE, ld.BuildModeCShared, ld.BuildModePlugin:
53
54 default:
55 return
56 }
57 }
58
59
60 thunks := make([]loader.Sym, 0, 7+len(ctxt.Textp))
61 for _, r := range [...]struct {
62 name string
63 num uint8
64 }{
65 {"ax", 0},
66 {"cx", 1},
67 {"dx", 2},
68 {"bx", 3},
69
70 {"bp", 5},
71 {"si", 6},
72 {"di", 7},
73 } {
74 thunkfunc := ldr.CreateSymForUpdate("__x86.get_pc_thunk."+r.name, 0)
75 thunkfunc.SetType(sym.STEXT)
76 ldr.SetAttrLocal(thunkfunc.Sym(), true)
77 o := func(op ...uint8) {
78 for _, op1 := range op {
79 thunkfunc.AddUint8(op1)
80 }
81 }
82
83
84 o(0x8b, 0x04+r.num<<3, 0x24)
85
86 o(0xc3)
87
88 thunks = append(thunks, thunkfunc.Sym())
89 }
90 ctxt.Textp = append(thunks, ctxt.Textp...)
91
92 initfunc, addmoduledata := ld.PrepareAddmoduledata(ctxt)
93 if initfunc == nil {
94 return
95 }
96
97 o := func(op ...uint8) {
98 for _, op1 := range op {
99 initfunc.AddUint8(op1)
100 }
101 }
102
103
104
105
106
107
108
109
110
111
112 o(0x53)
113
114 o(0xe8)
115 initfunc.AddSymRef(ctxt.Arch, ldr.Lookup("__x86.get_pc_thunk.cx", 0), 0, objabi.R_CALL, 4)
116
117 o(0x8d, 0x81)
118 initfunc.AddPCRelPlus(ctxt.Arch, ctxt.Moduledata, 6)
119
120 o(0x8d, 0x99)
121 gotsym := ldr.LookupOrCreateSym("_GLOBAL_OFFSET_TABLE_", 0)
122 initfunc.AddSymRef(ctxt.Arch, gotsym, 12, objabi.R_PCREL, 4)
123 o(0xe8)
124 initfunc.AddSymRef(ctxt.Arch, addmoduledata, 0, objabi.R_CALL, 4)
125
126 o(0x5b)
127
128 o(0xc3)
129 }
130
131 func adddynrel(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym, r loader.Reloc, rIdx int) bool {
132 targ := r.Sym()
133 var targType sym.SymKind
134 if targ != 0 {
135 targType = ldr.SymType(targ)
136 }
137
138 switch r.Type() {
139 default:
140 if r.Type() >= objabi.ElfRelocOffset {
141 ldr.Errorf(s, "unexpected relocation type %d (%s)", r.Type(), sym.RelocName(target.Arch, r.Type()))
142 return false
143 }
144
145
146 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PC32):
147 if targType == sym.SDYNIMPORT {
148 ldr.Errorf(s, "unexpected R_386_PC32 relocation for dynamic symbol %s", ldr.SymName(targ))
149 }
150 if targType == 0 || targType == sym.SXREF {
151 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
152 }
153 su := ldr.MakeSymbolUpdater(s)
154 su.SetRelocType(rIdx, objabi.R_PCREL)
155 su.SetRelocAdd(rIdx, r.Add()+4)
156 return true
157
158 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
159 su := ldr.MakeSymbolUpdater(s)
160 su.SetRelocType(rIdx, objabi.R_PCREL)
161 su.SetRelocAdd(rIdx, r.Add()+4)
162 if targType == sym.SDYNIMPORT {
163 addpltsym(target, ldr, syms, targ)
164 su.SetRelocSym(rIdx, syms.PLT)
165 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
166 }
167
168 return true
169
170 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
171 objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
172 su := ldr.MakeSymbolUpdater(s)
173 if targType != sym.SDYNIMPORT {
174
175 sData := ldr.Data(s)
176
177 if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
178 su.MakeWritable()
179
180
181 writeableData := su.Data()
182 writeableData[r.Off()-2] = 0x8d
183 su.SetRelocType(rIdx, objabi.R_GOTOFF)
184 return true
185 }
186
187 if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 {
188 su.MakeWritable()
189
190
191 writeableData := su.Data()
192 writeableData[r.Off()-2] = 0x36
193 writeableData[r.Off()-1] = 0x68
194 su.SetRelocType(rIdx, objabi.R_ADDR)
195 return true
196 }
197
198 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
199 return false
200 }
201
202 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT))
203 su.SetRelocType(rIdx, objabi.R_CONST)
204 su.SetRelocSym(rIdx, 0)
205 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
206 return true
207
208 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
209 su := ldr.MakeSymbolUpdater(s)
210 su.SetRelocType(rIdx, objabi.R_GOTOFF)
211 return true
212
213 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
214 su := ldr.MakeSymbolUpdater(s)
215 su.SetRelocType(rIdx, objabi.R_PCREL)
216 su.SetRelocSym(rIdx, syms.GOT)
217 su.SetRelocAdd(rIdx, r.Add()+4)
218 return true
219
220 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
221 if targType == sym.SDYNIMPORT {
222 ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ))
223 }
224 su := ldr.MakeSymbolUpdater(s)
225 su.SetRelocType(rIdx, objabi.R_ADDR)
226 return true
227
228 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
229 su := ldr.MakeSymbolUpdater(s)
230 su.SetRelocType(rIdx, objabi.R_ADDR)
231 if targType == sym.SDYNIMPORT {
232 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
233 }
234 return true
235
236 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
237 su := ldr.MakeSymbolUpdater(s)
238 if targType == sym.SDYNIMPORT {
239 addpltsym(target, ldr, syms, targ)
240 su.SetRelocSym(rIdx, syms.PLT)
241 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
242 su.SetRelocType(rIdx, objabi.R_PCREL)
243 return true
244 }
245
246 su.SetRelocType(rIdx, objabi.R_PCREL)
247 return true
248
249 case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
250 su := ldr.MakeSymbolUpdater(s)
251 if targType != sym.SDYNIMPORT {
252
253
254 sData := ldr.Data(s)
255 if r.Off() < 2 || sData[r.Off()-2] != 0x8b {
256 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
257 return false
258 }
259
260 su.MakeWritable()
261 writeableData := su.Data()
262 writeableData[r.Off()-2] = 0x8d
263 su.SetRelocType(rIdx, objabi.R_PCREL)
264 return true
265 }
266
267 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT))
268 su.SetRelocSym(rIdx, syms.GOT)
269 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
270 su.SetRelocType(rIdx, objabi.R_PCREL)
271 return true
272 }
273
274
275 if targType != sym.SDYNIMPORT {
276 return true
277 }
278
279
280 relocs := ldr.Relocs(s)
281 r = relocs.At(rIdx)
282
283 switch r.Type() {
284 case objabi.R_CALL,
285 objabi.R_PCREL:
286 if target.IsExternal() {
287
288 return true
289 }
290 addpltsym(target, ldr, syms, targ)
291 su := ldr.MakeSymbolUpdater(s)
292 su.SetRelocSym(rIdx, syms.PLT)
293 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
294 return true
295
296 case objabi.R_ADDR:
297 if ldr.SymType(s) != sym.SDATA {
298 break
299 }
300 if target.IsElf() {
301 ld.Adddynsym(ldr, target, syms, targ)
302 rel := ldr.MakeSymbolUpdater(syms.Rel)
303 rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
304 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
305 su := ldr.MakeSymbolUpdater(s)
306 su.SetRelocType(rIdx, objabi.R_CONST)
307 su.SetRelocSym(rIdx, 0)
308 return true
309 }
310 }
311
312 return false
313 }
314
315 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
316 out.Write32(uint32(sectoff))
317
318 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
319 siz := r.Size
320 switch r.Type {
321 default:
322 return false
323 case objabi.R_ADDR, objabi.R_DWARFSECREF:
324 if siz == 4 {
325 out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
326 } else {
327 return false
328 }
329 case objabi.R_GOTPCREL:
330 if siz == 4 {
331 out.Write32(uint32(elf.R_386_GOTPC))
332 if ldr.SymName(r.Xsym) != "_GLOBAL_OFFSET_TABLE_" {
333 out.Write32(uint32(sectoff))
334 out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8)
335 }
336 } else {
337 return false
338 }
339 case objabi.R_CALL:
340 if siz == 4 {
341 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
342 out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8)
343 } else {
344 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
345 }
346 } else {
347 return false
348 }
349 case objabi.R_PCREL:
350 if siz == 4 {
351 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
352 } else {
353 return false
354 }
355 case objabi.R_TLS_LE:
356 if siz == 4 {
357 out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8)
358 } else {
359 return false
360 }
361 case objabi.R_TLS_IE:
362 if siz == 4 {
363 out.Write32(uint32(elf.R_386_GOTPC))
364 out.Write32(uint32(sectoff))
365 out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8)
366 } else {
367 return false
368 }
369 }
370
371 return true
372 }
373
374 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
375 return false
376 }
377
378 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
379 var v uint32
380
381 rs := r.Xsym
382 rt := r.Type
383
384 if ldr.SymDynid(rs) < 0 {
385 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))
386 return false
387 }
388
389 out.Write32(uint32(sectoff))
390 out.Write32(uint32(ldr.SymDynid(rs)))
391
392 switch rt {
393 default:
394 return false
395
396 case objabi.R_DWARFSECREF:
397 v = ld.IMAGE_REL_I386_SECREL
398
399 case objabi.R_ADDR:
400 v = ld.IMAGE_REL_I386_DIR32
401
402 case objabi.R_PEIMAGEOFF:
403 v = ld.IMAGE_REL_I386_DIR32NB
404
405 case objabi.R_CALL,
406 objabi.R_PCREL:
407 v = ld.IMAGE_REL_I386_REL32
408 }
409
410 out.Write16(uint16(v))
411
412 return true
413 }
414
415 func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) {
416 return -1, 0, false
417 }
418
419 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
420 log.Fatalf("unexpected relocation variant")
421 return -1
422 }
423
424 func elfsetupplt(ctxt *ld.Link, ldr *loader.Loader, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
425 if plt.Size() == 0 {
426
427 plt.AddUint8(0xff)
428
429 plt.AddUint8(0x35)
430 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 4)
431
432
433 plt.AddUint8(0xff)
434
435 plt.AddUint8(0x25)
436 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 8)
437
438
439 plt.AddUint32(ctxt.Arch, 0)
440
441
442 got.AddAddrPlus(ctxt.Arch, dynamic, 0)
443
444 got.AddUint32(ctxt.Arch, 0)
445 got.AddUint32(ctxt.Arch, 0)
446 }
447 }
448
449 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
450 if ldr.SymPlt(s) >= 0 {
451 return
452 }
453
454 ld.Adddynsym(ldr, target, syms, s)
455
456 if target.IsElf() {
457 plt := ldr.MakeSymbolUpdater(syms.PLT)
458 got := ldr.MakeSymbolUpdater(syms.GOTPLT)
459 rel := ldr.MakeSymbolUpdater(syms.RelPLT)
460 if plt.Size() == 0 {
461 panic("plt is not set up")
462 }
463
464
465 plt.AddUint8(0xff)
466
467 plt.AddUint8(0x25)
468 plt.AddAddrPlus(target.Arch, got.Sym(), got.Size())
469
470
471 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
472
473
474 plt.AddUint8(0x68)
475
476 plt.AddUint32(target.Arch, uint32(rel.Size()))
477
478
479 plt.AddUint8(0xe9)
480
481 plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
482
483
484 rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
485
486 sDynid := ldr.SymDynid(s)
487 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
488
489 ldr.SetPlt(s, int32(plt.Size()-16))
490 } else {
491 ldr.Errorf(s, "addpltsym: unsupported binary format")
492 }
493 }
494
View as plain text