cpuelf.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. {
  2. Copyright (c) 1998-2006 by Peter Vreman
  3. Includes ELF-related code specific to i386
  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,cclasses,
  23. verbose,elfbase,
  24. systems,aasmbase,ogbase,ogelf,assemble;
  25. type
  26. TElfExeOutput386=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_386_NONE = 0;
  39. R_386_32 = 1; { ordinary absolute relocation }
  40. R_386_PC32 = 2; { PC-relative relocation }
  41. R_386_GOT32 = 3; { an offset into GOT }
  42. R_386_PLT32 = 4; { a PC-relative offset into PLT }
  43. R_386_COPY = 5;
  44. R_386_GLOB_DAT = 6;
  45. R_386_JUMP_SLOT = 7;
  46. R_386_RELATIVE = 8;
  47. R_386_GOTOFF = 9; { an offset from GOT base }
  48. R_386_GOTPC = 10; { a PC-relative offset _to_ GOT }
  49. R_386_TLS_TPOFF = 14;
  50. R_386_TLS_IE = 15;
  51. R_386_TLS_GOTIE = 16;
  52. R_386_TLS_LE = 17;
  53. R_386_TLS_GD = 18;
  54. R_386_TLS_LDM = 19;
  55. R_386_16 = 20;
  56. R_386_PC16 = 21;
  57. R_386_8 = 22;
  58. R_386_PC8 = 23;
  59. R_386_TLS_GD_32 = 24;
  60. R_386_TLS_GD_PUSH = 25;
  61. R_386_TLS_GD_CALL = 26;
  62. R_386_TLS_GD_POP = 27;
  63. R_386_TLS_LDM_32 = 28;
  64. R_386_TLS_LDM_PUSH = 29;
  65. R_386_TLS_LDM_CALL = 30;
  66. R_386_TLS_LDM_POP = 31;
  67. R_386_TLS_LDO_32 = 32;
  68. R_386_TLS_IE_32 = 33;
  69. R_386_TLS_LE_32 = 34;
  70. R_386_TLS_DTPMOD32 = 35;
  71. R_386_TLS_DTPOFF32 = 36;
  72. R_386_TLS_TPOFF32 = 37;
  73. { 38 is unused }
  74. R_386_TLS_GOTDESC = 39;
  75. R_386_TLS_DESC_CALL = 40;
  76. R_386_TLS_DESC = 41;
  77. R_386_IRELATIVE = 42;
  78. R_386_GNU_VTINHERIT = 250;
  79. R_386_GNU_VTENTRY = 251;
  80. {****************************************************************************
  81. ELF Target methods
  82. ****************************************************************************}
  83. function elf_i386_encodereloc(objrel:TObjRelocation):byte;
  84. begin
  85. case objrel.typ of
  86. RELOC_NONE :
  87. result:=R_386_NONE;
  88. RELOC_RELATIVE :
  89. result:=R_386_PC32;
  90. RELOC_ABSOLUTE :
  91. result:=R_386_32;
  92. RELOC_GOT32 :
  93. result:=R_386_GOT32;
  94. RELOC_GOTPC :
  95. result:=R_386_GOTPC;
  96. RELOC_PLT32 :
  97. result:=R_386_PLT32;
  98. RELOC_GOTOFF:
  99. result:=R_386_GOTOFF;
  100. RELOC_NTPOFF:
  101. if objrel.size=4 then
  102. result:=R_386_TLS_LE
  103. else
  104. InternalError(2019092101);
  105. RELOC_TLSGD:
  106. result:=R_386_TLS_GD;
  107. RELOC_DTPOFF:
  108. result:=R_386_TLS_DTPOFF32;
  109. else
  110. result:=0;
  111. InternalError(2012082301);
  112. end;
  113. end;
  114. procedure elf_i386_loadreloc(objrel:TObjRelocation);
  115. begin
  116. end;
  117. function elf_i386_relocname(reltyp:byte):string;
  118. begin
  119. result:='TODO';
  120. end;
  121. {****************************************************************************
  122. TElfExeOutput386
  123. ****************************************************************************}
  124. procedure TElfExeOutput386.WriteFirstPLTEntry;
  125. begin
  126. if IsSharedLibrary then
  127. // push 4(%ebx); jmp *8(%ebx)
  128. pltobjsec.writeBytes(#$FF#$B3#$04#$00#$00#$00#$FF#$A3#$08#$00#$00#$00)
  129. else
  130. begin
  131. pltobjsec.writeBytes(#$FF#$35); // push got+4
  132. pltobjsec.writeReloc_internal(gotpltobjsec,sizeof(pint),4,RELOC_ABSOLUTE);
  133. pltobjsec.writeBytes(#$FF#$25); // jmp *got+8
  134. pltobjsec.writeReloc_internal(gotpltobjsec,2*sizeof(pint),4,RELOC_ABSOLUTE);
  135. end;
  136. pltobjsec.writeBytes(#$90#$90#$90#$90); // nop
  137. end;
  138. procedure TElfExeOutput386.WritePLTEntry(exesym:TExeSymbol);
  139. var
  140. got_offset: aword;
  141. tmp:pint;
  142. begin
  143. got_offset:=gotpltobjsec.size;
  144. if IsSharedLibrary then
  145. begin
  146. pltobjsec.writeBytes(#$FF#$A3); // jmp got+x(%ebx)
  147. pltobjsec.write(got_offset,4);
  148. end
  149. else
  150. begin
  151. pltobjsec.writeBytes(#$FF#$25); // jmp *got+x
  152. pltobjsec.writeReloc_internal(gotpltobjsec,got_offset,4,RELOC_ABSOLUTE);
  153. end;
  154. pltobjsec.writeBytes(#$68); // push $index
  155. tmp:=pltrelocsec.size;
  156. pltobjsec.write(tmp,4);
  157. pltobjsec.writeBytes(#$E9); // jmp .plt
  158. tmp:=-(4+pltobjsec.Size);
  159. pltobjsec.write(tmp,4);
  160. { write a .got.plt slot pointing back to the 'push' instruction }
  161. gotpltobjsec.writeReloc_internal(pltobjsec,pltobjsec.size-(16-6),sizeof(pint),RELOC_ABSOLUTE);
  162. { write a .rel.plt entry }
  163. pltrelocsec.writeReloc_internal(gotpltobjsec,got_offset,sizeof(pint),RELOC_ABSOLUTE);
  164. got_offset:=(exesym.dynindex shl 8) or R_386_JUMP_SLOT;
  165. pltrelocsec.write(got_offset,sizeof(pint));
  166. if ElfTarget.relocs_use_addend then
  167. pltrelocsec.writezeros(sizeof(pint));
  168. end;
  169. procedure TElfExeOutput386.WriteIndirectPLTEntry(exesym:TExeSymbol);
  170. begin
  171. // TODO
  172. inherited WriteIndirectPLTEntry(exesym);
  173. end;
  174. procedure TElfExeOutput386.GOTRelocPass1(objsec:TObjSection;var idx:longint);
  175. var
  176. objsym:TObjSymbol;
  177. objreloc:TObjRelocation;
  178. reltyp:byte;
  179. begin
  180. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  181. if (ObjReloc.flags and rf_raw)=0 then
  182. reltyp:=ElfTarget.encodereloc(ObjReloc)
  183. else
  184. reltyp:=ObjReloc.ftype;
  185. case reltyp of
  186. R_386_PLT32:
  187. begin
  188. objsym:=objreloc.symbol.exesymbol.ObjSymbol;
  189. objsym.refs:=objsym.refs or symref_plt;
  190. end;
  191. R_386_32:
  192. if (oso_executable in objsec.SecOptions) or
  193. not (oso_write in objsec.SecOptions) then
  194. begin
  195. if assigned(objreloc.symbol) and assigned(objreloc.symbol.exesymbol) then
  196. begin
  197. objsym:=objreloc.symbol.exesymbol.ObjSymbol;
  198. objsym.refs:=objsym.refs or symref_from_text;
  199. end;
  200. end;
  201. end;
  202. case reltyp of
  203. R_386_TLS_IE:
  204. begin
  205. AllocGOTSlot(objreloc.symbol);
  206. end;
  207. R_386_GOT32:
  208. begin
  209. AllocGOTSlot(objreloc.symbol);
  210. end;
  211. R_386_32:
  212. begin
  213. { TODO: How to handle absolute relocation to *weak* external symbol
  214. from executable? See test/tweaklib2, symbol test2, ld handles it
  215. differently for PIC and non-PIC code. In non-PIC code it drops
  216. dynamic relocation altogether. }
  217. if not IsSharedLibrary then
  218. exit;
  219. if (oso_executable in objsec.SecOptions) or
  220. not (oso_write in objsec.SecOptions) then
  221. hastextrelocs:=True;
  222. dynrelocsec.alloc(dynrelocsec.shentsize);
  223. objreloc.flags:=objreloc.flags or rf_dynamic;
  224. end;
  225. R_386_PC32:
  226. begin
  227. if not IsSharedLibrary then
  228. exit;
  229. { In shared library PC32 reloc to external symbol cannot be redirected
  230. to PLT entry, because PIC PLT relies on ebx register set properly. }
  231. if assigned(objreloc.symbol) and
  232. (
  233. (objreloc.symbol.objsection=nil) or
  234. (oso_plt in objreloc.symbol.objsection.SecOptions)
  235. ) then
  236. begin
  237. { Must be a dynamic symbol }
  238. if not (assigned(objreloc.symbol.exesymbol) and
  239. (objreloc.symbol.exesymbol.dynindex<>0)) then
  240. InternalError(2012101201);
  241. if (oso_executable in objsec.SecOptions) or
  242. not (oso_write in objsec.SecOptions) then
  243. hastextrelocs:=True;
  244. dynrelocsec.alloc(dynrelocsec.shentsize);
  245. objreloc.flags:=objreloc.flags or rf_dynamic;
  246. end;
  247. end;
  248. end;
  249. end;
  250. procedure TElfExeOutput386.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  251. var
  252. gotoff,tmp:aword;
  253. begin
  254. gotoff:=objsym.exesymbol.gotoffset;
  255. if gotoff=0 then
  256. InternalError(2012060902);
  257. { the GOT slot itself, and a dynamic relocation for it }
  258. { TODO: only data symbols must get here }
  259. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  260. begin
  261. gotobjsec.write(relocval,sizeof(pint));
  262. tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
  263. if (objsym.exesymbol.dynindex>0) then
  264. begin
  265. if (reltyp=R_386_TLS_IE) then
  266. if IsSharedLibrary then
  267. WriteDynRelocEntry(tmp,R_386_TLS_TPOFF,objsym.exesymbol.dynindex,0)
  268. else
  269. else
  270. WriteDynRelocEntry(tmp,R_386_GLOB_DAT,objsym.exesymbol.dynindex,0)
  271. end
  272. else if IsSharedLibrary then
  273. WriteDynRelocEntry(tmp,R_386_RELATIVE,0,relocval);
  274. end;
  275. end;
  276. procedure TElfExeOutput386.DoRelocationFixup(objsec:TObjSection);
  277. var
  278. i,zero:longint;
  279. objreloc: TObjRelocation;
  280. address,
  281. relocval : aint;
  282. relocsec : TObjSection;
  283. data: TDynamicArray;
  284. reltyp: byte;
  285. PC: aword;
  286. begin
  287. data:=objsec.data;
  288. for i:=0 to objsec.ObjRelocations.Count-1 do
  289. begin
  290. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  291. case objreloc.typ of
  292. RELOC_NONE:
  293. continue;
  294. RELOC_ZERO:
  295. begin
  296. data.Seek(objreloc.dataoffset);
  297. zero:=0;
  298. data.Write(zero,4);
  299. continue;
  300. end;
  301. else
  302. ;
  303. end;
  304. if (objreloc.flags and rf_raw)=0 then
  305. reltyp:=ElfTarget.encodereloc(objreloc)
  306. else
  307. reltyp:=objreloc.ftype;
  308. if ElfTarget.relocs_use_addend then
  309. address:=objreloc.orgsize
  310. else
  311. begin
  312. data.Seek(objreloc.dataoffset);
  313. data.Read(address,4);
  314. end;
  315. if assigned(objreloc.symbol) then
  316. begin
  317. relocsec:=objreloc.symbol.objsection;
  318. relocval:=objreloc.symbol.address;
  319. end
  320. else if assigned(objreloc.objsection) then
  321. begin
  322. relocsec:=objreloc.objsection;
  323. relocval:=objreloc.objsection.mempos
  324. end
  325. else
  326. internalerror(2012060702);
  327. { Only debug sections are allowed to have relocs pointing to unused sections }
  328. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  329. not (oso_debug in objsec.secoptions) then
  330. begin
  331. writeln(objsec.fullname,' references ',relocsec.fullname);
  332. internalerror(2012060703);
  333. end;
  334. PC:=objsec.mempos+objreloc.dataoffset;
  335. { TODO: if relocsec=nil, relocations must be copied to .rel.dyn section }
  336. if (relocsec=nil) or (relocsec.used) then
  337. case reltyp of
  338. R_386_PC32:
  339. begin
  340. if (objreloc.flags and rf_dynamic)<>0 then
  341. WriteDynRelocEntry(PC,R_386_PC32,objreloc.symbol.exesymbol.dynindex,0)
  342. else
  343. address:=address+relocval-PC;
  344. end;
  345. R_386_PLT32:
  346. begin
  347. { If target is in current object, treat as RELOC_RELATIVE }
  348. address:=address+relocval-PC;
  349. end;
  350. R_386_32:
  351. begin
  352. if (objreloc.flags and rf_dynamic)<>0 then
  353. begin
  354. if (objreloc.symbol=nil) or
  355. (objreloc.symbol.exesymbol=nil) or
  356. (objreloc.symbol.exesymbol.dynindex=0) then
  357. begin
  358. address:=address+relocval;
  359. WriteDynRelocEntry(PC,R_386_RELATIVE,0,address);
  360. end
  361. else
  362. { Don't modify address in this case, as it serves as addend for RTLD }
  363. WriteDynRelocEntry(PC,R_386_32,objreloc.symbol.exesymbol.dynindex,0);
  364. end
  365. else
  366. address:=address+relocval;
  367. end;
  368. R_386_GOTPC:
  369. begin
  370. address:=address+gotsymbol.address-PC;
  371. end;
  372. R_386_GOT32:
  373. begin
  374. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  375. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
  376. address:=address+relocval;
  377. end;
  378. R_386_GOTOFF:
  379. begin
  380. address:=address+relocval-gotsymbol.address;
  381. end;
  382. R_386_TLS_IE:
  383. begin
  384. relocval:=-(tlsseg.MemPos+tlsseg.MemSize-relocval);
  385. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  386. { Resolves to *absolute* offset of GOT slot }
  387. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
  388. address:=address+relocval;
  389. end;
  390. R_386_TLS_LE_32,
  391. R_386_TLS_LE:
  392. begin
  393. if IsSharedLibrary then
  394. begin
  395. {
  396. if reltyp=R_386_TLS_LE_32 then
  397. begin
  398. WriteDynRelocEntry(PC,R_386_TLS_TPOFF32,symbol.exesymbol.dynindex,0);
  399. address:=tlsseg.MemPos-relocval;
  400. end;
  401. else
  402. begin
  403. WriteDynRelocEntry(PC,R_386_TLS_TPOFF,symbol.exesymbol.dynindex,0);
  404. address:=address-tlsseg.MemPos;
  405. end;
  406. }
  407. end
  408. else if (reltyp=R_386_TLS_LE) then
  409. address:=-(tlsseg.MemPos+tlsseg.MemSize-relocval)
  410. else
  411. address:=tlsseg.MemPos+tlsseg.MemSize-relocval;
  412. end;
  413. else
  414. begin
  415. writeln(reltyp);
  416. internalerror(200604014);
  417. end;
  418. end
  419. else { not relocsec.Used }
  420. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  421. data.Seek(objreloc.dataoffset);
  422. data.Write(address,4);
  423. end;
  424. end;
  425. {*****************************************************************************
  426. Initialize
  427. *****************************************************************************}
  428. const
  429. elf_target_i386 : TElfTarget =
  430. (
  431. max_page_size: $1000;
  432. exe_image_base: $8048000;
  433. machine_code: EM_386;
  434. relocs_use_addend: false;
  435. dyn_reloc_codes: (
  436. R_386_RELATIVE,
  437. R_386_GLOB_DAT,
  438. R_386_JUMP_SLOT,
  439. R_386_COPY,
  440. R_386_IRELATIVE
  441. );
  442. relocname: @elf_i386_relocName;
  443. encodereloc: @elf_i386_encodeReloc;
  444. loadreloc: @elf_i386_loadReloc;
  445. loadsection: nil;
  446. encodeflags: nil;
  447. );
  448. as_i386_elf32_info : tasminfo =
  449. (
  450. id : as_i386_elf32;
  451. idtxt : 'ELF';
  452. asmbin : '';
  453. asmcmd : '';
  454. supported_targets : [system_i386_linux,system_i386_beos,
  455. system_i386_freebsd,system_i386_haiku,
  456. system_i386_openbsd,system_i386_netbsd,
  457. system_i386_Netware,system_i386_netwlibc,
  458. system_i386_solaris,system_i386_embedded,
  459. system_i386_android,system_i386_aros];
  460. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
  461. labelprefix : '.L';
  462. comment : '';
  463. dollarsign: '$';
  464. );
  465. initialization
  466. RegisterAssembler(as_i386_elf32_info,TElfAssembler);
  467. ElfExeOutputClass:=TElfExeOutput386;
  468. ElfTarget:=elf_target_i386;
  469. end.