cpuelf.pas 17 KB

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