cpuelf.pas 17 KB

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