cpuelf.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. {
  2. Copyright (c) 1998-2006 by Peter Vreman
  3. Includes ELF-related code specific to x86_64
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cpuelf;
  18. {$i fpcdefs.inc}
  19. interface
  20. implementation
  21. uses
  22. globtype,cutils,cclasses,
  23. verbose,elfbase,
  24. systems,aasmbase,ogbase,ogelf,assemble;
  25. type
  26. TElfExeOutputx86_64=class(TElfExeOutput)
  27. private
  28. procedure MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  29. protected
  30. procedure WriteFirstPLTEntry;override;
  31. procedure WritePLTEntry(exesym:TExeSymbol);override;
  32. procedure WriteIndirectPLTEntry(exesym:TExeSymbol);override;
  33. procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);override;
  34. procedure DoRelocationFixup(objsec:TObjSection);override;
  35. end;
  36. const
  37. { Relocation types }
  38. R_X86_64_NONE = 0;
  39. R_X86_64_64 = 1; { Direct 64 bit }
  40. R_X86_64_PC32 = 2; { PC relative 32 bit signed }
  41. R_X86_64_GOT32 = 3; { 32 bit GOT entry }
  42. R_X86_64_PLT32 = 4; { 32 bit PLT address }
  43. R_X86_64_COPY = 5; { Copy symbol at runtime }
  44. R_X86_64_GLOB_DAT = 6; { Create GOT entry }
  45. R_X86_64_JUMP_SLOT = 7; { Create PLT entry }
  46. R_X86_64_RELATIVE = 8; { Adjust by program base }
  47. R_X86_64_GOTPCREL = 9; { 32 bit signed PC relative offset to GOT }
  48. R_X86_64_32 = 10; { Direct 32 bit zero extended }
  49. R_X86_64_32S = 11; { Direct 32 bit sign extended }
  50. R_X86_64_16 = 12; { Direct 16 bit zero extended }
  51. R_X86_64_PC16 = 13; { 16 bit sign extended PC relative }
  52. R_X86_64_8 = 14; { Direct 8 bit sign extended }
  53. R_X86_64_PC8 = 15; { 8 bit sign extended PC relative }
  54. R_X86_64_DTPMOD64 = 16; { ID of module containing symbol }
  55. R_X86_64_DTPOFF64 = 17; { Offset in module's TLS block }
  56. R_X86_64_TPOFF64 = 18; { Offset in initial TLS block }
  57. { 32 bit signed PC relative offset to two GOT entries for GD symbol }
  58. R_X86_64_TLSGD = 19;
  59. { 32 bit signed PC relative offset to two GOT entries for LD symbol }
  60. R_X86_64_TLSLD = 20;
  61. R_X86_64_DTPOFF32 = 21; { Offset in TLS block }
  62. { 32 bit signed PC relative offset to GOT entry for IE symbol }
  63. R_X86_64_GOTTPOFF = 22;
  64. R_X86_64_TPOFF32 = 23; { Offset in initial TLS block }
  65. R_X86_64_PC64 = 24; { PC relative 64-bit signed }
  66. R_X86_64_GOTOFF64 = 25; { 64-bit offset from GOT base }
  67. R_X86_64_GOTPC32 = 26; { PC-relative offset GOT }
  68. R_X86_64_GOT64 = 27; { 64-bit GOT entry offset }
  69. R_X86_64_GOTPCREL64 = 28; { 64-bit PC relative offset to GOT entry }
  70. R_X86_64_GOTPC64 = 29; { 64-bit PC relative offset to GOT }
  71. R_X86_64_GOTPLT64 = 30; { Like GOT64, indicates that PLT entry needed }
  72. R_X86_64_PLTOFF64 = 31; { 64-bit GOT relative offset to PLT entry }
  73. R_X86_64_SIZE32 = 32;
  74. R_X86_64_SIZE64 = 33;
  75. R_X86_64_GOTPC32_TLSDESC = 34;
  76. R_X86_64_TLSDESC_CALL = 35;
  77. R_X86_64_TLSDESC = 36;
  78. R_X86_64_IRELATIVE = 37;
  79. R_X86_64_GNU_VTINHERIT = 250; { GNU extension to record C++ vtable hierarchy }
  80. R_X86_64_GNU_VTENTRY = 251; { GNU extension to record C++ vtable member usage }
  81. type
  82. TRelocProp=record
  83. name: PChar;
  84. size: byte;
  85. end;
  86. const
  87. relocprops: array[0..37] of TRelocProp=(
  88. (name: 'R_X86_64_NONE'; size:0),
  89. (name: 'R_X86_64_64'; size:8),
  90. (name: 'R_X86_64_PC32'; size:4),
  91. (name: 'R_X86_64_GOT32'; size:4),
  92. (name: 'R_X86_64_PLT32'; size:4),
  93. (name: 'R_X86_64_COPY'; size:0),
  94. (name: 'R_X86_64_GLOB_DAT'; size:8),
  95. (name: 'R_X86_64_JUMP_SLOT';size:8),
  96. (name: 'R_X86_64_RELATIVE'; size:8),
  97. (name: 'R_X86_64_GOTPCREL'; size:4),
  98. (name: 'R_X86_64_32'; size:4),
  99. (name: 'R_X86_64_32S'; size:4),
  100. (name: 'R_X86_64_16'; size:2),
  101. (name: 'R_X86_64_PC16'; size:2),
  102. (name: 'R_X86_64_8'; size:1),
  103. (name: 'R_X86_64_PC8'; size:1),
  104. (name: 'R_X86_64_DTPMOD64'; size:8),
  105. (name: 'R_X86_64_DTPOFF64'; size:8),
  106. (name: 'R_X86_64_TPOFF64'; size:8),
  107. (name: 'R_X86_64_TLSGD'; size:4),
  108. (name: 'R_X86_64_TLSLD'; size:4),
  109. (name: 'R_X86_64_DTPOFF32'; size:4),
  110. (name: 'R_X86_64_GOTTPOFF'; size:4),
  111. (name: 'R_X86_64_TPOFF32'; size:4),
  112. (name: 'R_X86_64_PC64'; size:8),
  113. (name: 'R_X86_64_GOTOFF64'; size:8),
  114. (name: 'R_X86_64_GOTPC32'; size:4),
  115. (name: 'R_X86_64_GOT64'; size:8),
  116. (name: 'R_X86_64_GOTPCREL64'; size:8),
  117. (name: 'R_X86_64_GOTPC64'; size:8),
  118. (name: 'R_X86_64_GOTPLT64'; size:8),
  119. (name: 'R_X86_64_PLTOFF64'; size:8),
  120. (name: 'R_X86_64_SIZE32'; size:4),
  121. (name: 'R_X86_64_SIZE64'; size:8),
  122. (name: 'R_X86_64_GOTPC32_TLSDESC'; size:4),
  123. (name: 'R_X86_64_TLSDESC_CALL'; size:0),
  124. (name: 'R_X86_64_TLSDESC'; size:8),
  125. (name: 'R_X86_64_IRELATIVE'; size:8)
  126. );
  127. {****************************************************************************
  128. ELF Target methods
  129. ****************************************************************************}
  130. function elf_x86_64_encodereloc(objrel:TObjRelocation):byte;
  131. begin
  132. case objrel.typ of
  133. RELOC_NONE :
  134. result:=R_X86_64_NONE;
  135. { Note: 8 and 16-bit relocations are known to be non-conformant with
  136. AMD64 ABI, so they aren't handled. }
  137. RELOC_RELATIVE :
  138. if objrel.size=8 then
  139. result:=R_X86_64_PC64
  140. else if objrel.size=4 then
  141. result:=R_X86_64_PC32
  142. else
  143. InternalError(2012061900);
  144. RELOC_ABSOLUTE :
  145. if objrel.size=8 then
  146. result:=R_X86_64_64
  147. else if objrel.size=4 then
  148. result:=R_X86_64_32
  149. else
  150. InternalError(2012061901);
  151. RELOC_ABSOLUTE32 :
  152. result:=R_X86_64_32S;
  153. RELOC_GOTPCREL :
  154. result:=R_X86_64_GOTPCREL;
  155. RELOC_PLT32 :
  156. result:=R_X86_64_PLT32;
  157. else
  158. result:=0;
  159. InternalError(2012082302);
  160. end;
  161. end;
  162. procedure elf_x86_64_loadreloc(objrel:TObjRelocation);
  163. begin
  164. end;
  165. function elf_x86_64_relocname(reltyp:byte):string;
  166. begin
  167. if reltyp<=high(relocprops) then
  168. result:=relocprops[reltyp].name
  169. else
  170. result:='unknown ('+tostr(reltyp)+')';
  171. end;
  172. {****************************************************************************
  173. TELFExeOutputx86_64
  174. ****************************************************************************}
  175. procedure TElfExeOutputx86_64.GOTRelocPass1(objsec:TObjSection;var idx:longint);
  176. var
  177. objsym:TObjSymbol;
  178. objreloc:TObjRelocation;
  179. reltyp:byte;
  180. begin
  181. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  182. if (ObjReloc.flags and rf_raw)=0 then
  183. reltyp:=ElfTarget.encodereloc(ObjReloc)
  184. else
  185. reltyp:=ObjReloc.ftype;
  186. case reltyp of
  187. R_X86_64_PLT32,
  188. R_X86_64_PLTOFF64,
  189. R_X86_64_GOTPLT64:
  190. begin
  191. objsym:=ObjReloc.symbol.exesymbol.ObjSymbol;
  192. objsym.refs:=objsym.refs or symref_plt;
  193. end;
  194. end;
  195. case reltyp of
  196. R_X86_64_GOTTPOFF:
  197. begin
  198. { TLS IE to locally defined symbol, convert into LE so GOT entry isn't needed
  199. (Is TLS IE allowed in shared libs at all? Yes it is, when lib is accessing
  200. a threadvar in main program or in other *statically* loaded lib; TLS IE access to
  201. own threadvars may render library not loadable dynamically) }
  202. (*
  203. if not (IsSharedLibrary or (sym.dynindex>0)) then
  204. begin
  205. if not IsValidIEtoLE(objsec,ObjReloc) then
  206. Comment(v_error,'Cannot transform TLS IE to LE');
  207. TranslateIEtoLE(objsec,ObjReloc);
  208. ObjReloc.ftype:=R_X86_64_TPOFF32;
  209. exit;
  210. end;
  211. *)
  212. AllocGOTSlot(objreloc.symbol);
  213. end;
  214. R_X86_64_GOT32,
  215. R_X86_64_GOT64,
  216. R_X86_64_GOTPCREL,
  217. R_X86_64_GOTPCREL64:
  218. begin
  219. if AllocGOTSlot(objreloc.symbol) then
  220. if IsSharedLibrary and (objreloc.symbol.exesymbol.dynindex=0) then
  221. Inc(relative_reloc_count);
  222. end;
  223. //R_X86_64_TLSGD,
  224. //R_X86_64_TLSLD: { TODO: allocate two GOT slots }
  225. { R_X86_64_32S cannot be used in DSOs at all }
  226. R_X86_64_32S:
  227. if IsSharedLibrary then
  228. ReportNonDSOReloc(reltyp,objsec,objreloc);
  229. { R_X86_64_32 is processed by rtld, but binutils accept it in data sections only.
  230. Relocating the against local symbols is tricky: changing into RELATIVE is not possible,
  231. so it is changed into relocation against section symbol. This requires adding
  232. the appropriate section symbol to dynamic symtable. BFD also has some obscure logic
  233. behind, e.g. it uses .text section for symbols from .data section.
  234. For now, leave this situation unhandled, as 32-bit relocations aren't commonly
  235. used in 64-bit code. }
  236. R_X86_64_32:
  237. if IsSharedLibrary then
  238. begin
  239. if (oso_executable in objsec.SecOptions) or
  240. not (oso_write in objsec.SecOptions) then
  241. ReportNonDSOReloc(reltyp,objsec,objreloc)
  242. else
  243. InternalError(2012092601);
  244. end;
  245. R_X86_64_64:
  246. begin
  247. if IsSharedLibrary then
  248. begin
  249. if (oso_executable in objsec.SecOptions) or
  250. not (oso_write in objsec.SecOptions) then
  251. hastextrelocs:=True;
  252. dynrelocsec.alloc(dynrelocsec.shentsize);
  253. objreloc.flags:=objreloc.flags or rf_dynamic;
  254. if (objreloc.symbol=nil) or
  255. (objreloc.symbol.exesymbol=nil) or
  256. (objreloc.symbol.exesymbol.dynindex=0) then
  257. Inc(relative_reloc_count);
  258. end;
  259. end;
  260. end;
  261. end;
  262. procedure TElfExeOutputx86_64.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  263. var
  264. gotoff,tmp:aword;
  265. begin
  266. gotoff:=objsym.exesymbol.gotoffset;
  267. if gotoff=0 then
  268. InternalError(2012060902);
  269. { the GOT slot itself, and a dynamic relocation for it }
  270. { TODO: only data symbols must get here }
  271. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  272. begin
  273. gotobjsec.write(relocval,sizeof(pint));
  274. tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
  275. if (objsym.exesymbol.dynindex>0) then
  276. begin
  277. if (reltyp=R_X86_64_GOTTPOFF) then
  278. if IsSharedLibrary then
  279. dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_TPOFF64)) // probably incorrect
  280. else
  281. else
  282. dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_GLOB_DAT));
  283. end
  284. else if IsSharedLibrary then
  285. WriteDynRelocEntry(tmp,R_X86_64_RELATIVE,0,relocval);
  286. end;
  287. end;
  288. procedure TElfExeOutputx86_64.DoRelocationFixup(objsec:TObjSection);
  289. var
  290. i,zero:longint;
  291. objreloc: TObjRelocation;
  292. address,
  293. relocval : aint;
  294. relocsec : TObjSection;
  295. data: TDynamicArray;
  296. reltyp,relsize: byte;
  297. PC: aword;
  298. begin
  299. data:=objsec.data;
  300. for i:=0 to objsec.ObjRelocations.Count-1 do
  301. begin
  302. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  303. case objreloc.typ of
  304. RELOC_NONE:
  305. continue;
  306. RELOC_ZERO:
  307. begin
  308. data.Seek(objreloc.dataoffset);
  309. zero:=0;
  310. data.Write(zero,4);
  311. continue;
  312. end;
  313. end;
  314. if (objreloc.flags and rf_raw)=0 then
  315. reltyp:=ElfTarget.encodereloc(objreloc)
  316. else
  317. reltyp:=objreloc.ftype;
  318. if reltyp<=high(relocprops) then
  319. relsize:=relocprops[reltyp].size
  320. else
  321. InternalError(2012092103);
  322. if ElfTarget.relocs_use_addend then
  323. address:=objreloc.orgsize
  324. else
  325. begin
  326. data.Seek(objreloc.dataoffset);
  327. data.Read(address,relsize);
  328. end;
  329. if assigned(objreloc.symbol) then
  330. begin
  331. relocsec:=objreloc.symbol.objsection;
  332. relocval:=objreloc.symbol.address;
  333. end
  334. else if assigned(objreloc.objsection) then
  335. begin
  336. relocsec:=objreloc.objsection;
  337. relocval:=objreloc.objsection.mempos
  338. end
  339. else
  340. internalerror(2012060702);
  341. { Only debug sections are allowed to have relocs pointing to unused sections }
  342. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  343. not (oso_debug in objsec.secoptions) then
  344. begin
  345. writeln(objsec.fullname,' references ',relocsec.fullname);
  346. internalerror(2012060703);
  347. end;
  348. PC:=objsec.mempos+objreloc.dataoffset;
  349. { TODO: if relocsec=nil, relocations must be copied to .rela.dyn section }
  350. if (relocsec=nil) or (relocsec.used) then
  351. case reltyp of
  352. R_X86_64_PC32,
  353. R_X86_64_PC64:
  354. begin
  355. // TODO: ld rejects PC32 relocations to dynamic symbols, they must use @PLT
  356. address:=address+relocval-PC;
  357. end;
  358. R_X86_64_PLT32:
  359. begin
  360. { If target is in current object, treat as RELOC_RELATIVE }
  361. address:=address+relocval-PC;
  362. end;
  363. R_X86_64_TPOFF32,
  364. R_X86_64_TPOFF64:
  365. address:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
  366. R_X86_64_GOTTPOFF,
  367. R_X86_64_GOTPCREL,
  368. R_X86_64_GOTPCREL64:
  369. begin
  370. if (reltyp=R_X86_64_GOTTPOFF) then
  371. relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
  372. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  373. { resolves to PC-relative offset to GOT slot }
  374. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
  375. address:=address+relocval-PC;
  376. end;
  377. R_X86_64_32S,
  378. R_X86_64_32:
  379. inc(address,relocval);
  380. R_X86_64_64:
  381. begin
  382. inc(address,relocval);
  383. if (objreloc.flags and rf_dynamic)<>0 then
  384. begin
  385. if (objreloc.symbol=nil) or
  386. (objreloc.symbol.exesymbol=nil) or
  387. (objreloc.symbol.exesymbol.dynindex=0) then
  388. WriteDynRelocEntry(PC,R_X86_64_RELATIVE,0,address)
  389. else
  390. dynreloclist.add(TObjRelocation.CreateRaw(PC,objreloc.symbol,R_X86_64_64));
  391. end;
  392. end;
  393. R_X86_64_GOTPC32,
  394. R_X86_64_GOTPC64:
  395. begin
  396. address:=address+gotsymbol.address-PC;
  397. end;
  398. R_X86_64_GOT32,
  399. R_X86_64_GOT64:
  400. begin
  401. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  402. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
  403. address:=address+relocval;
  404. end;
  405. R_X86_64_GOTOFF64,
  406. R_X86_64_PLTOFF64:
  407. begin
  408. address:=address+relocval-gotsymbol.address;
  409. end;
  410. else
  411. begin
  412. writeln(objreloc.typ);
  413. internalerror(200604014);
  414. end;
  415. end
  416. else { not relocsec.Used }
  417. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  418. case relsize of
  419. 8: ;
  420. 4:
  421. begin
  422. case reltyp of
  423. R_X86_64_32:
  424. if qword(address)>qword($FFFFFFFF) then
  425. ReportRelocOverflow(reltyp,objsec,objreloc);
  426. else
  427. if (address>high(longint)) or (address<low(longint)) then
  428. ReportRelocOverflow(reltyp,objsec,objreloc);
  429. end;
  430. end;
  431. else
  432. InternalError(2012101102);
  433. end;
  434. data.Seek(objreloc.dataoffset);
  435. data.Write(address,relsize);
  436. end;
  437. end;
  438. procedure TElfExeOutputx86_64.WriteFirstPLTEntry;
  439. begin
  440. pltobjsec.writeBytes(#$FF#$35); // push got+8(%rip)
  441. pltobjsec.writeReloc_internal(gotpltobjsec,sizeof(pint),4,RELOC_RELATIVE);
  442. pltobjsec.writeBytes(#$FF#$25); // jmp *got+16(%rip)
  443. pltobjsec.writeReloc_internal(gotpltobjsec,2*sizeof(pint),4,RELOC_RELATIVE);
  444. pltobjsec.writeBytes(#$0F#$1F#$40#$00); // nopl 0(%rax)
  445. end;
  446. procedure TElfExeOutputx86_64.WritePLTEntry(exesym:TExeSymbol);
  447. var
  448. got_offset: aword;
  449. tmp: pint;
  450. begin
  451. pltobjsec.writeBytes(#$FF#$25); // jmp *got+x(%rip)
  452. pltobjsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size,4,RELOC_RELATIVE);
  453. pltobjsec.writeBytes(#$68); // push $index
  454. tmp:=pltrelocsec.size div pltrelocsec.shentsize;
  455. pltobjsec.write(tmp,4);
  456. pltobjsec.writeBytes(#$E9); // jmp .plt
  457. tmp:=-(4+pltobjsec.Size);
  458. pltobjsec.write(tmp,4);
  459. { write a .got.plt slot pointing back to the 'push' instruction }
  460. gotpltobjsec.writeReloc_internal(pltobjsec,pltobjsec.size-(16-6),sizeof(pint),RELOC_ABSOLUTE);
  461. { write a .rela.plt entry (Elf64_rela record) }
  462. pltrelocsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size-sizeof(pint),sizeof(pint),RELOC_ABSOLUTE);
  463. got_offset:=(qword(exesym.dynindex) shl 32) or R_X86_64_JUMP_SLOT;
  464. pltrelocsec.write(got_offset,sizeof(pint));
  465. if ElfTarget.relocs_use_addend then
  466. pltrelocsec.writezeros(sizeof(pint));
  467. end;
  468. procedure TElfExeOutputx86_64.WriteIndirectPLTEntry(exesym:TExeSymbol);
  469. var
  470. tmp: pint;
  471. objsym:TObjSymbol;
  472. targetsym:TObjSymbol;
  473. begin
  474. targetsym:=exesym.ObjSymbol;
  475. objsym:=internalobjdata.CreateSymbol(exesym.name);
  476. objsym.typ:=AT_FUNCTION;
  477. objsym.bind:=exesym.ObjSymbol.bind; { AB_EXTERNAL or AB_WEAK_EXTERNAL }
  478. objsym.offset:=pltobjsec.size;
  479. objsym.objsection:=pltobjsec;
  480. exesym.ObjSymbol:=objsym;
  481. pltobjsec.writeBytes(#$FF#$25); // jmp *got+x(%rip)
  482. pltobjsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size,4,RELOC_RELATIVE);
  483. { TODO: Are these entries relevant when linking dynamic?
  484. (for static linking, they don't matter) }
  485. pltobjsec.writeBytes(#$68); // push $index
  486. tmp:=pltrelocsec.size div pltrelocsec.shentsize;
  487. pltobjsec.write(tmp,4);
  488. pltobjsec.writeBytes(#$E9); // jmp .plt
  489. tmp:=-(4+pltobjsec.Size);
  490. pltobjsec.write(tmp,4);
  491. { write a .got.plt slot pointing back to the 'push' instruction }
  492. gotpltobjsec.writeReloc_internal(pltobjsec,pltobjsec.size-(16-6),sizeof(pint),RELOC_ABSOLUTE);
  493. { write a .rela.iplt entry (Elf64_rela record) }
  494. ipltrelocsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size-sizeof(pint),sizeof(pint),RELOC_ABSOLUTE);
  495. tmp:=R_X86_64_IRELATIVE;
  496. ipltrelocsec.write(tmp,sizeof(pint));
  497. if ElfTarget.relocs_use_addend then
  498. ipltrelocsec.writeReloc_internal(targetsym.objsection,targetsym.offset,sizeof(pint),RELOC_ABSOLUTE);
  499. end;
  500. {*****************************************************************************
  501. Initialize
  502. *****************************************************************************}
  503. const
  504. elf_target_x86_64: TElfTarget =
  505. (
  506. max_page_size: $200000;
  507. exe_image_base: $400000;
  508. machine_code: EM_X86_64;
  509. relocs_use_addend: true;
  510. dyn_reloc_codes: (
  511. R_X86_64_RELATIVE,
  512. R_X86_64_GLOB_DAT,
  513. R_X86_64_JUMP_SLOT,
  514. R_X86_64_COPY,
  515. R_X86_64_IRELATIVE
  516. );
  517. relocname: @elf_x86_64_relocName;
  518. encodereloc: @elf_x86_64_encodeReloc;
  519. loadreloc: @elf_x86_64_loadReloc;
  520. loadsection: nil;
  521. );
  522. as_x86_64_elf64_info : tasminfo =
  523. (
  524. id : as_x86_64_elf64;
  525. idtxt : 'ELF';
  526. asmbin : '';
  527. asmcmd : '';
  528. supported_targets : [system_x86_64_linux,system_x86_64_freebsd,
  529. system_x86_64_openbsd,system_x86_64_netbsd];
  530. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
  531. labelprefix : '.L';
  532. comment : '';
  533. dollarsign: '$';
  534. );
  535. initialization
  536. RegisterAssembler(as_x86_64_elf64_info,TElfAssembler);
  537. ElfTarget:=elf_target_x86_64;
  538. ElfExeOutputClass:=TElfExeOutputx86_64;
  539. end.