cpuelf.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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. externsym,fromtext:boolean;
  181. begin
  182. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  183. if (ObjReloc.flags and rf_raw)=0 then
  184. reltyp:=ElfTarget.encodereloc(ObjReloc)
  185. else
  186. reltyp:=ObjReloc.ftype;
  187. case reltyp of
  188. R_X86_64_PLT32,
  189. R_X86_64_PLTOFF64,
  190. R_X86_64_GOTPLT64:
  191. begin
  192. if assigned(ObjReloc.symbol) and assigned(ObjReloc.symbol.exesymbol) then
  193. begin
  194. objsym:=ObjReloc.symbol.exesymbol.ObjSymbol;
  195. objsym.refs:=objsym.refs or symref_plt;
  196. end;
  197. end;
  198. end;
  199. case reltyp of
  200. R_X86_64_GOTTPOFF:
  201. begin
  202. { TLS IE to locally defined symbol, convert into LE so GOT entry isn't needed
  203. (Is TLS IE allowed in shared libs at all? Yes it is, when lib is accessing
  204. a threadvar in main program or in other *statically* loaded lib; TLS IE access to
  205. own threadvars may render library not loadable dynamically) }
  206. (*
  207. if not (IsSharedLibrary or (sym.dynindex>0)) then
  208. begin
  209. if not IsValidIEtoLE(objsec,ObjReloc) then
  210. Comment(v_error,'Cannot transform TLS IE to LE');
  211. TranslateIEtoLE(objsec,ObjReloc);
  212. ObjReloc.ftype:=R_X86_64_TPOFF32;
  213. exit;
  214. end;
  215. *)
  216. AllocGOTSlot(objreloc.symbol);
  217. end;
  218. R_X86_64_GOT32,
  219. R_X86_64_GOT64,
  220. R_X86_64_GOTPCREL,
  221. R_X86_64_GOTPCREL64:
  222. begin
  223. if AllocGOTSlot(objreloc.symbol) then
  224. if IsSharedLibrary and (objreloc.symbol.exesymbol.dynindex=0) then
  225. Inc(relative_reloc_count);
  226. end;
  227. //R_X86_64_TLSGD,
  228. //R_X86_64_TLSLD: { TODO: allocate two GOT slots }
  229. R_X86_64_TPOFF32,
  230. { R_X86_64_32S cannot be used in DSOs at all }
  231. R_X86_64_32S:
  232. if IsSharedLibrary then
  233. ReportNonDSOReloc(reltyp,objsec,objreloc);
  234. { R_X86_64_32 is processed by rtld, but binutils accept it in data sections only.
  235. Relocating the against local symbols is tricky: changing into RELATIVE is not possible,
  236. so it is changed into relocation against section symbol. This requires adding
  237. the appropriate section symbol to dynamic symtable. BFD also has some obscure logic
  238. behind, e.g. it uses .text section for symbols from .data section.
  239. For now, leave this situation unhandled, as 32-bit relocations aren't commonly
  240. used in 64-bit code. }
  241. R_X86_64_32:
  242. if IsSharedLibrary then
  243. begin
  244. if (oso_executable in objsec.SecOptions) or
  245. not (oso_write in objsec.SecOptions) then
  246. ReportNonDSOReloc(reltyp,objsec,objreloc)
  247. else
  248. InternalError(2012092601);
  249. end;
  250. R_X86_64_64:
  251. begin
  252. fromtext:=(oso_executable in objsec.SecOptions) or
  253. not (oso_write in objsec.SecOptions);
  254. externsym:=assigned(objreloc.symbol) and
  255. assigned(objreloc.symbol.exesymbol) and
  256. (objreloc.symbol.exesymbol.dynindex<>0);
  257. if IsSharedLibrary then
  258. begin
  259. if fromtext then
  260. hastextrelocs:=True;
  261. dynrelocsec.alloc(dynrelocsec.shentsize);
  262. objreloc.flags:=objreloc.flags or rf_dynamic;
  263. if (not externsym) then
  264. Inc(relative_reloc_count);
  265. end
  266. else if externsym then
  267. // TODO: R_X86_64_32 and R_X86_64_32S here?
  268. begin
  269. objsym:=objreloc.symbol.ExeSymbol.ObjSymbol;
  270. { If symbol has non-GOT references from readonly sections, then it needs a
  271. copy reloc, which eliminates any dynamic relocations to this symbol from
  272. writable sections as well. OTOH if it is referenced *only* from writable
  273. sections, then it's better not to generate a copy reloc and keep dynamic
  274. relocations. The following code is based on assumption that all readonly
  275. sections are processed before writable ones (which is true for current
  276. segment mapping).
  277. For arbitrary segment mapping, this will probably require a separate pass. }
  278. if fromtext then
  279. objsym.refs:=objsym.refs or symref_from_text
  280. else if (objsym.refs and symref_from_text)=0 then
  281. begin
  282. dynrelocsec.alloc(dynrelocsec.shentsize);
  283. objreloc.flags:=objreloc.flags or rf_dynamic;
  284. end;
  285. end;
  286. end;
  287. end;
  288. end;
  289. procedure TElfExeOutputx86_64.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  290. var
  291. gotoff,tmp:aword;
  292. begin
  293. gotoff:=objsym.exesymbol.gotoffset;
  294. if gotoff=0 then
  295. InternalError(2012060902);
  296. { the GOT slot itself, and a dynamic relocation for it }
  297. { TODO: only data symbols must get here }
  298. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  299. begin
  300. gotobjsec.write(relocval,sizeof(pint));
  301. tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
  302. if (objsym.exesymbol.dynindex>0) then
  303. begin
  304. if (reltyp=R_X86_64_GOTTPOFF) then
  305. if IsSharedLibrary then
  306. dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_TPOFF64)) // probably incorrect
  307. else
  308. else
  309. dynreloclist.Add(TObjRelocation.CreateRaw(tmp,objsym,R_X86_64_GLOB_DAT));
  310. end
  311. else if IsSharedLibrary then
  312. WriteDynRelocEntry(tmp,R_X86_64_RELATIVE,0,relocval);
  313. end;
  314. end;
  315. procedure TElfExeOutputx86_64.DoRelocationFixup(objsec:TObjSection);
  316. var
  317. i,zero:longint;
  318. objreloc: TObjRelocation;
  319. address,
  320. relocval : aint;
  321. relocsec : TObjSection;
  322. data: TDynamicArray;
  323. reltyp,relsize: byte;
  324. PC: aword;
  325. begin
  326. data:=objsec.data;
  327. for i:=0 to objsec.ObjRelocations.Count-1 do
  328. begin
  329. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  330. case objreloc.typ of
  331. RELOC_NONE:
  332. continue;
  333. RELOC_ZERO:
  334. begin
  335. data.Seek(objreloc.dataoffset);
  336. zero:=0;
  337. data.Write(zero,4);
  338. continue;
  339. end;
  340. end;
  341. if (objreloc.flags and rf_raw)=0 then
  342. reltyp:=ElfTarget.encodereloc(objreloc)
  343. else
  344. reltyp:=objreloc.ftype;
  345. if reltyp<=high(relocprops) then
  346. relsize:=relocprops[reltyp].size
  347. else
  348. InternalError(2012092103);
  349. if ElfTarget.relocs_use_addend then
  350. address:=objreloc.orgsize
  351. else
  352. begin
  353. data.Seek(objreloc.dataoffset);
  354. data.Read(address,relsize);
  355. end;
  356. if assigned(objreloc.symbol) then
  357. begin
  358. relocsec:=objreloc.symbol.objsection;
  359. relocval:=objreloc.symbol.address;
  360. end
  361. else if assigned(objreloc.objsection) then
  362. begin
  363. relocsec:=objreloc.objsection;
  364. relocval:=objreloc.objsection.mempos
  365. end
  366. else
  367. internalerror(2012060702);
  368. { Only debug sections are allowed to have relocs pointing to unused sections }
  369. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  370. not (oso_debug in objsec.secoptions) then
  371. begin
  372. writeln(objsec.fullname,' references ',relocsec.fullname);
  373. internalerror(2012060703);
  374. end;
  375. PC:=objsec.mempos+objreloc.dataoffset;
  376. { TODO: if relocsec=nil, relocations must be copied to .rela.dyn section }
  377. if (relocsec=nil) or (relocsec.used) then
  378. case reltyp of
  379. R_X86_64_PC32,
  380. R_X86_64_PC64:
  381. begin
  382. // TODO: ld rejects PC32 relocations to dynamic symbols, they must use @PLT
  383. address:=address+relocval-PC;
  384. end;
  385. R_X86_64_PLT32:
  386. begin
  387. { If target is in current object, treat as RELOC_RELATIVE }
  388. address:=address+relocval-PC;
  389. end;
  390. //R_X86_64_DTPOFF64 is possible in data??
  391. R_X86_64_DTPOFF32:
  392. begin
  393. { In executable it behaves as TPOFF32, but data expressions
  394. like ".long foo@dtpoff" resolve to positive offset }
  395. if IsSharedLibrary or not (oso_executable in objsec.SecOptions) then
  396. address:=address+relocval-tlsseg.MemPos
  397. else
  398. address:=address+relocval-(tlsseg.MemPos+tlsseg.MemSize);
  399. end;
  400. R_X86_64_TPOFF32,
  401. R_X86_64_TPOFF64:
  402. address:=address+relocval-(tlsseg.MemPos+tlsseg.MemSize);
  403. R_X86_64_GOTTPOFF,
  404. R_X86_64_GOTPCREL,
  405. R_X86_64_GOTPCREL64:
  406. begin
  407. if (reltyp=R_X86_64_GOTTPOFF) then
  408. relocval:=relocval-(tlsseg.MemPos+tlsseg.MemSize);
  409. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  410. { resolves to PC-relative offset to GOT slot }
  411. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
  412. address:=address+relocval-PC;
  413. end;
  414. R_X86_64_32S,
  415. R_X86_64_32:
  416. inc(address,relocval);
  417. R_X86_64_64:
  418. begin
  419. inc(address,relocval);
  420. if (objreloc.flags and rf_dynamic)<>0 then
  421. begin
  422. if (objreloc.symbol=nil) or
  423. (objreloc.symbol.exesymbol=nil) or
  424. (objreloc.symbol.exesymbol.dynindex=0) then
  425. WriteDynRelocEntry(PC,R_X86_64_RELATIVE,0,address)
  426. else
  427. dynreloclist.add(TObjRelocation.CreateRaw(PC,objreloc.symbol,R_X86_64_64));
  428. end;
  429. end;
  430. R_X86_64_GOTPC32,
  431. R_X86_64_GOTPC64:
  432. begin
  433. address:=address+gotsymbol.address-PC;
  434. end;
  435. R_X86_64_GOT32,
  436. R_X86_64_GOT64:
  437. begin
  438. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  439. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
  440. address:=address+relocval;
  441. end;
  442. R_X86_64_GOTOFF64,
  443. R_X86_64_PLTOFF64:
  444. begin
  445. address:=address+relocval-gotsymbol.address;
  446. end;
  447. else
  448. begin
  449. writeln(objreloc.typ);
  450. internalerror(200604014);
  451. end;
  452. end
  453. else { not relocsec.Used }
  454. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  455. case relsize of
  456. 8: ;
  457. 4:
  458. begin
  459. case reltyp of
  460. R_X86_64_32:
  461. if qword(address)>qword($FFFFFFFF) then
  462. ReportRelocOverflow(reltyp,objsec,objreloc);
  463. else
  464. if (address>high(longint)) or (address<low(longint)) then
  465. ReportRelocOverflow(reltyp,objsec,objreloc);
  466. end;
  467. end;
  468. else
  469. InternalError(2012101102);
  470. end;
  471. data.Seek(objreloc.dataoffset);
  472. data.Write(address,relsize);
  473. end;
  474. end;
  475. procedure TElfExeOutputx86_64.WriteFirstPLTEntry;
  476. begin
  477. pltobjsec.writeBytes(#$FF#$35); // push got+8(%rip)
  478. pltobjsec.writeReloc_internal(gotpltobjsec,sizeof(pint),4,RELOC_RELATIVE);
  479. pltobjsec.writeBytes(#$FF#$25); // jmp *got+16(%rip)
  480. pltobjsec.writeReloc_internal(gotpltobjsec,2*sizeof(pint),4,RELOC_RELATIVE);
  481. pltobjsec.writeBytes(#$0F#$1F#$40#$00); // nopl 0(%rax)
  482. end;
  483. procedure TElfExeOutputx86_64.WritePLTEntry(exesym:TExeSymbol);
  484. var
  485. got_offset: aword;
  486. tmp: pint;
  487. begin
  488. pltobjsec.writeBytes(#$FF#$25); // jmp *got+x(%rip)
  489. pltobjsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size,4,RELOC_RELATIVE);
  490. pltobjsec.writeBytes(#$68); // push $index
  491. tmp:=pltrelocsec.size div pltrelocsec.shentsize;
  492. pltobjsec.write(tmp,4);
  493. pltobjsec.writeBytes(#$E9); // jmp .plt
  494. tmp:=-(4+pltobjsec.Size);
  495. pltobjsec.write(tmp,4);
  496. { write a .got.plt slot pointing back to the 'push' instruction }
  497. gotpltobjsec.writeReloc_internal(pltobjsec,pltobjsec.size-(16-6),sizeof(pint),RELOC_ABSOLUTE);
  498. { write a .rela.plt entry (Elf64_rela record) }
  499. pltrelocsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size-sizeof(pint),sizeof(pint),RELOC_ABSOLUTE);
  500. got_offset:=(qword(exesym.dynindex) shl 32) or R_X86_64_JUMP_SLOT;
  501. pltrelocsec.write(got_offset,sizeof(pint));
  502. if ElfTarget.relocs_use_addend then
  503. pltrelocsec.writezeros(sizeof(pint));
  504. end;
  505. procedure TElfExeOutputx86_64.WriteIndirectPLTEntry(exesym:TExeSymbol);
  506. var
  507. tmp: pint;
  508. objsym:TObjSymbol;
  509. targetsym:TObjSymbol;
  510. begin
  511. targetsym:=exesym.ObjSymbol;
  512. objsym:=internalobjdata.CreateSymbol(exesym.name);
  513. objsym.typ:=AT_FUNCTION;
  514. objsym.bind:=exesym.ObjSymbol.bind; { AB_EXTERNAL or AB_WEAK_EXTERNAL }
  515. objsym.offset:=pltobjsec.size;
  516. objsym.objsection:=pltobjsec;
  517. exesym.ObjSymbol:=objsym;
  518. pltobjsec.writeBytes(#$FF#$25); // jmp *got+x(%rip)
  519. pltobjsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size,4,RELOC_RELATIVE);
  520. { TODO: Are these entries relevant when linking dynamic?
  521. (for static linking, they don't matter) }
  522. pltobjsec.writeBytes(#$68); // push $index
  523. tmp:=pltrelocsec.size div pltrelocsec.shentsize;
  524. pltobjsec.write(tmp,4);
  525. pltobjsec.writeBytes(#$E9); // jmp .plt
  526. tmp:=-(4+pltobjsec.Size);
  527. pltobjsec.write(tmp,4);
  528. { write a .got.plt slot pointing back to the 'push' instruction }
  529. gotpltobjsec.writeReloc_internal(pltobjsec,pltobjsec.size-(16-6),sizeof(pint),RELOC_ABSOLUTE);
  530. { write a .rela.iplt entry (Elf64_rela record) }
  531. ipltrelocsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size-sizeof(pint),sizeof(pint),RELOC_ABSOLUTE);
  532. tmp:=R_X86_64_IRELATIVE;
  533. ipltrelocsec.write(tmp,sizeof(pint));
  534. if ElfTarget.relocs_use_addend then
  535. ipltrelocsec.writeReloc_internal(targetsym.objsection,targetsym.offset,sizeof(pint),RELOC_ABSOLUTE);
  536. end;
  537. {*****************************************************************************
  538. Initialize
  539. *****************************************************************************}
  540. const
  541. elf_target_x86_64: TElfTarget =
  542. (
  543. max_page_size: $200000;
  544. exe_image_base: $400000;
  545. machine_code: EM_X86_64;
  546. relocs_use_addend: true;
  547. dyn_reloc_codes: (
  548. R_X86_64_RELATIVE,
  549. R_X86_64_GLOB_DAT,
  550. R_X86_64_JUMP_SLOT,
  551. R_X86_64_COPY,
  552. R_X86_64_IRELATIVE
  553. );
  554. relocname: @elf_x86_64_relocName;
  555. encodereloc: @elf_x86_64_encodeReloc;
  556. loadreloc: @elf_x86_64_loadReloc;
  557. loadsection: nil;
  558. );
  559. as_x86_64_elf64_info : tasminfo =
  560. (
  561. id : as_x86_64_elf64;
  562. idtxt : 'ELF';
  563. asmbin : '';
  564. asmcmd : '';
  565. supported_targets : [system_x86_64_linux,system_x86_64_freebsd,
  566. system_x86_64_openbsd,system_x86_64_netbsd];
  567. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
  568. labelprefix : '.L';
  569. comment : '';
  570. dollarsign: '$';
  571. );
  572. initialization
  573. RegisterAssembler(as_x86_64_elf64_info,TElfAssembler);
  574. ElfTarget:=elf_target_x86_64;
  575. ElfExeOutputClass:=TElfExeOutputx86_64;
  576. end.