cpuelf.pas 26 KB

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