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