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
151
152 if (targType == 0 || targType == sym.SXREF) && !ldr.AttrVisibilityHidden(targ) {
153 ldr.Errorf(s, "unknown symbol %s in pcrel", ldr.SymName(targ))
154 }
155 su := ldr.MakeSymbolUpdater(s)
156 su.SetRelocType(rIdx, objabi.R_PCREL)
157 su.SetRelocAdd(rIdx, r.Add()+4)
158 return true
159
160 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_PLT32):
161 su := ldr.MakeSymbolUpdater(s)
162 su.SetRelocType(rIdx, objabi.R_PCREL)
163 su.SetRelocAdd(rIdx, r.Add()+4)
164 if targType == sym.SDYNIMPORT {
165 addpltsym(target, ldr, syms, targ)
166 su.SetRelocSym(rIdx, syms.PLT)
167 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymPlt(targ)))
168 }
169
170 return true
171
172 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32),
173 objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOT32X):
174 su := ldr.MakeSymbolUpdater(s)
175 if targType != sym.SDYNIMPORT {
176
177 sData := ldr.Data(s)
178
179 if r.Off() >= 2 && sData[r.Off()-2] == 0x8b {
180 su.MakeWritable()
181
182
183 writeableData := su.Data()
184 writeableData[r.Off()-2] = 0x8d
185 su.SetRelocType(rIdx, objabi.R_GOTOFF)
186 return true
187 }
188
189 if r.Off() >= 2 && sData[r.Off()-2] == 0xff && sData[r.Off()-1] == 0xb3 {
190 su.MakeWritable()
191
192
193 writeableData := su.Data()
194 writeableData[r.Off()-2] = 0x36
195 writeableData[r.Off()-1] = 0x68
196 su.SetRelocType(rIdx, objabi.R_ADDR)
197 return true
198 }
199
200 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
201 return false
202 }
203
204 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT))
205 su.SetRelocType(rIdx, objabi.R_CONST)
206 su.SetRelocSym(rIdx, 0)
207 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
208 return true
209
210 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTOFF):
211 su := ldr.MakeSymbolUpdater(s)
212 su.SetRelocType(rIdx, objabi.R_GOTOFF)
213 return true
214
215 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_GOTPC):
216 su := ldr.MakeSymbolUpdater(s)
217 su.SetRelocType(rIdx, objabi.R_PCREL)
218 su.SetRelocSym(rIdx, syms.GOT)
219 su.SetRelocAdd(rIdx, r.Add()+4)
220 return true
221
222 case objabi.ElfRelocOffset + objabi.RelocType(elf.R_386_32):
223 if targType == sym.SDYNIMPORT {
224 ldr.Errorf(s, "unexpected R_386_32 relocation for dynamic symbol %s", ldr.SymName(targ))
225 }
226 su := ldr.MakeSymbolUpdater(s)
227 su.SetRelocType(rIdx, objabi.R_ADDR)
228 return true
229
230 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
231 su := ldr.MakeSymbolUpdater(s)
232 su.SetRelocType(rIdx, objabi.R_ADDR)
233 if targType == sym.SDYNIMPORT {
234 ldr.Errorf(s, "unexpected reloc for dynamic symbol %s", ldr.SymName(targ))
235 }
236 return true
237
238 case objabi.MachoRelocOffset + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
239 su := ldr.MakeSymbolUpdater(s)
240 if targType == sym.SDYNIMPORT {
241 addpltsym(target, ldr, syms, targ)
242 su.SetRelocSym(rIdx, syms.PLT)
243 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
244 su.SetRelocType(rIdx, objabi.R_PCREL)
245 return true
246 }
247
248 su.SetRelocType(rIdx, objabi.R_PCREL)
249 return true
250
251 case objabi.MachoRelocOffset + ld.MACHO_FAKE_GOTPCREL:
252 su := ldr.MakeSymbolUpdater(s)
253 if targType != sym.SDYNIMPORT {
254
255
256 sData := ldr.Data(s)
257 if r.Off() < 2 || sData[r.Off()-2] != 0x8b {
258 ldr.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", ldr.SymName(targ))
259 return false
260 }
261
262 su.MakeWritable()
263 writeableData := su.Data()
264 writeableData[r.Off()-2] = 0x8d
265 su.SetRelocType(rIdx, objabi.R_PCREL)
266 return true
267 }
268
269 ld.AddGotSym(target, ldr, syms, targ, uint32(elf.R_386_GLOB_DAT))
270 su.SetRelocSym(rIdx, syms.GOT)
271 su.SetRelocAdd(rIdx, r.Add()+int64(ldr.SymGot(targ)))
272 su.SetRelocType(rIdx, objabi.R_PCREL)
273 return true
274 }
275
276
277 if targType != sym.SDYNIMPORT {
278 return true
279 }
280
281
282 relocs := ldr.Relocs(s)
283 r = relocs.At(rIdx)
284
285 switch r.Type() {
286 case objabi.R_CALL,
287 objabi.R_PCREL:
288 if target.IsExternal() {
289
290 return true
291 }
292 addpltsym(target, ldr, syms, targ)
293 su := ldr.MakeSymbolUpdater(s)
294 su.SetRelocSym(rIdx, syms.PLT)
295 su.SetRelocAdd(rIdx, int64(ldr.SymPlt(targ)))
296 return true
297
298 case objabi.R_ADDR:
299 if ldr.SymType(s) != sym.SDATA {
300 break
301 }
302 if target.IsElf() {
303 ld.Adddynsym(ldr, target, syms, targ)
304 rel := ldr.MakeSymbolUpdater(syms.Rel)
305 rel.AddAddrPlus(target.Arch, s, int64(r.Off()))
306 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(ldr.SymDynid(targ)), uint32(elf.R_386_32)))
307 su := ldr.MakeSymbolUpdater(s)
308 su.SetRelocType(rIdx, objabi.R_CONST)
309 su.SetRelocSym(rIdx, 0)
310 return true
311 }
312 }
313
314 return false
315 }
316
317 func elfreloc1(ctxt *ld.Link, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, ri int, sectoff int64) bool {
318 out.Write32(uint32(sectoff))
319
320 elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
321 siz := r.Size
322 switch r.Type {
323 default:
324 return false
325 case objabi.R_ADDR, objabi.R_DWARFSECREF:
326 if siz == 4 {
327 out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
328 } else {
329 return false
330 }
331 case objabi.R_GOTPCREL:
332 if siz == 4 {
333 out.Write32(uint32(elf.R_386_GOTPC))
334 if ldr.SymName(r.Xsym) != "_GLOBAL_OFFSET_TABLE_" {
335 out.Write32(uint32(sectoff))
336 out.Write32(uint32(elf.R_386_GOT32) | uint32(elfsym)<<8)
337 }
338 } else {
339 return false
340 }
341 case objabi.R_CALL:
342 if siz == 4 {
343 if ldr.SymType(r.Xsym) == sym.SDYNIMPORT {
344 out.Write32(uint32(elf.R_386_PLT32) | uint32(elfsym)<<8)
345 } else {
346 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
347 }
348 } else {
349 return false
350 }
351 case objabi.R_PCREL:
352 if siz == 4 {
353 out.Write32(uint32(elf.R_386_PC32) | uint32(elfsym)<<8)
354 } else {
355 return false
356 }
357 case objabi.R_TLS_LE:
358 if siz == 4 {
359 out.Write32(uint32(elf.R_386_TLS_LE) | uint32(elfsym)<<8)
360 } else {
361 return false
362 }
363 case objabi.R_TLS_IE:
364 if siz == 4 {
365 out.Write32(uint32(elf.R_386_GOTPC))
366 out.Write32(uint32(sectoff))
367 out.Write32(uint32(elf.R_386_TLS_GOTIE) | uint32(elfsym)<<8)
368 } else {
369 return false
370 }
371 }
372
373 return true
374 }
375
376 func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtReloc, int64) bool {
377 return false
378 }
379
380 func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool {
381 var v uint32
382
383 rs := r.Xsym
384 rt := r.Type
385
386 if ldr.SymDynid(rs) < 0 {
387 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))
388 return false
389 }
390
391 out.Write32(uint32(sectoff))
392 out.Write32(uint32(ldr.SymDynid(rs)))
393
394 switch rt {
395 default:
396 return false
397
398 case objabi.R_DWARFSECREF:
399 v = ld.IMAGE_REL_I386_SECREL
400
401 case objabi.R_ADDR:
402 v = ld.IMAGE_REL_I386_DIR32
403
404 case objabi.R_CALL,
405 objabi.R_PCREL:
406 v = ld.IMAGE_REL_I386_REL32
407 }
408
409 out.Write16(uint16(v))
410
411 return true
412 }
413
414 func archreloc(*ld.Target, *loader.Loader, *ld.ArchSyms, loader.Reloc, loader.Sym, int64) (int64, int, bool) {
415 return -1, 0, false
416 }
417
418 func archrelocvariant(*ld.Target, *loader.Loader, loader.Reloc, sym.RelocVariant, loader.Sym, int64, []byte) int64 {
419 log.Fatalf("unexpected relocation variant")
420 return -1
421 }
422
423 func elfsetupplt(ctxt *ld.Link, plt, got *loader.SymbolBuilder, dynamic loader.Sym) {
424 if plt.Size() == 0 {
425
426 plt.AddUint8(0xff)
427
428 plt.AddUint8(0x35)
429 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 4)
430
431
432 plt.AddUint8(0xff)
433
434 plt.AddUint8(0x25)
435 plt.AddAddrPlus(ctxt.Arch, got.Sym(), 8)
436
437
438 plt.AddUint32(ctxt.Arch, 0)
439
440
441 got.AddAddrPlus(ctxt.Arch, dynamic, 0)
442
443 got.AddUint32(ctxt.Arch, 0)
444 got.AddUint32(ctxt.Arch, 0)
445 }
446 }
447
448 func addpltsym(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s loader.Sym) {
449 if ldr.SymPlt(s) >= 0 {
450 return
451 }
452
453 ld.Adddynsym(ldr, target, syms, s)
454
455 if target.IsElf() {
456 plt := ldr.MakeSymbolUpdater(syms.PLT)
457 got := ldr.MakeSymbolUpdater(syms.GOTPLT)
458 rel := ldr.MakeSymbolUpdater(syms.RelPLT)
459 if plt.Size() == 0 {
460 panic("plt is not set up")
461 }
462
463
464 plt.AddUint8(0xff)
465
466 plt.AddUint8(0x25)
467 plt.AddAddrPlus(target.Arch, got.Sym(), got.Size())
468
469
470 got.AddAddrPlus(target.Arch, plt.Sym(), plt.Size())
471
472
473 plt.AddUint8(0x68)
474
475 plt.AddUint32(target.Arch, uint32(rel.Size()))
476
477
478 plt.AddUint8(0xe9)
479
480 plt.AddUint32(target.Arch, uint32(-(plt.Size() + 4)))
481
482
483 rel.AddAddrPlus(target.Arch, got.Sym(), got.Size()-4)
484
485 sDynid := ldr.SymDynid(s)
486 rel.AddUint32(target.Arch, elf.R_INFO32(uint32(sDynid), uint32(elf.R_386_JMP_SLOT)))
487
488 ldr.SetPlt(s, int32(plt.Size()-16))
489 } else {
490 ldr.Errorf(s, "addpltsym: unsupported binary format")
491 }
492 }
493
View as plain text