cpuelf.pas 26 KB

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