cpuelf.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  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_TLS_IE:
  181. begin
  182. AllocGOTSlot(objreloc.symbol);
  183. end;
  184. R_386_GOT32:
  185. begin
  186. AllocGOTSlot(objreloc.symbol);
  187. end;
  188. R_386_32:
  189. begin
  190. { TODO: How to handle absolute relocation to *weak* external symbol
  191. from executable? See test/tweaklib2, symbol test2, ld handles it
  192. differently for PIC and non-PIC code. In non-PIC code it drops
  193. dynamic relocation altogether. }
  194. if not IsSharedLibrary then
  195. exit;
  196. if (oso_executable in objsec.SecOptions) or
  197. not (oso_write in objsec.SecOptions) then
  198. hastextrelocs:=True;
  199. dynrelocsec.alloc(dynrelocsec.shentsize);
  200. objreloc.flags:=objreloc.flags or rf_dynamic;
  201. end;
  202. R_386_PC32:
  203. begin
  204. if not IsSharedLibrary then
  205. exit;
  206. { In shared library PC32 reloc to external symbol cannot be redirected
  207. to PLT entry, because PIC PLT relies on ebx register set properly. }
  208. if assigned(objreloc.symbol) and
  209. (
  210. (objreloc.symbol.objsection=nil) or
  211. (oso_plt in objreloc.symbol.objsection.SecOptions)
  212. ) then
  213. begin
  214. { Must be a dynamic symbol }
  215. if not (assigned(objreloc.symbol.exesymbol) and
  216. (objreloc.symbol.exesymbol.dynindex<>0)) then
  217. InternalError(2012101201);
  218. if (oso_executable in objsec.SecOptions) or
  219. not (oso_write in objsec.SecOptions) then
  220. hastextrelocs:=True;
  221. dynrelocsec.alloc(dynrelocsec.shentsize);
  222. objreloc.flags:=objreloc.flags or rf_dynamic;
  223. end;
  224. end;
  225. end;
  226. end;
  227. procedure TElfExeOutput386.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  228. var
  229. gotoff,tmp:aword;
  230. begin
  231. gotoff:=objsym.exesymbol.gotoffset;
  232. if gotoff=0 then
  233. InternalError(2012060902);
  234. { the GOT slot itself, and a dynamic relocation for it }
  235. { TODO: only data symbols must get here }
  236. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  237. begin
  238. gotobjsec.write(relocval,sizeof(pint));
  239. tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
  240. if (objsym.exesymbol.dynindex>0) then
  241. begin
  242. if (reltyp=R_386_TLS_IE) then
  243. if IsSharedLibrary then
  244. WriteDynRelocEntry(tmp,R_386_TLS_TPOFF,objsym.exesymbol.dynindex,0)
  245. else
  246. else
  247. WriteDynRelocEntry(tmp,R_386_GLOB_DAT,objsym.exesymbol.dynindex,0)
  248. end
  249. else if IsSharedLibrary then
  250. WriteDynRelocEntry(tmp,R_386_RELATIVE,0,relocval);
  251. end;
  252. end;
  253. procedure TElfExeOutput386.DoRelocationFixup(objsec:TObjSection);
  254. var
  255. i,zero:longint;
  256. objreloc: TObjRelocation;
  257. address,
  258. relocval : aint;
  259. relocsec : TObjSection;
  260. data: TDynamicArray;
  261. reltyp: byte;
  262. PC: aword;
  263. begin
  264. data:=objsec.data;
  265. for i:=0 to objsec.ObjRelocations.Count-1 do
  266. begin
  267. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  268. case objreloc.typ of
  269. RELOC_NONE:
  270. continue;
  271. RELOC_ZERO:
  272. begin
  273. data.Seek(objreloc.dataoffset);
  274. zero:=0;
  275. data.Write(zero,4);
  276. continue;
  277. end;
  278. end;
  279. if (objreloc.flags and rf_raw)=0 then
  280. reltyp:=ElfTarget.encodereloc(objreloc)
  281. else
  282. reltyp:=objreloc.ftype;
  283. if ElfTarget.relocs_use_addend then
  284. address:=objreloc.orgsize
  285. else
  286. begin
  287. data.Seek(objreloc.dataoffset);
  288. data.Read(address,4);
  289. end;
  290. if assigned(objreloc.symbol) then
  291. begin
  292. relocsec:=objreloc.symbol.objsection;
  293. relocval:=objreloc.symbol.address;
  294. end
  295. else if assigned(objreloc.objsection) then
  296. begin
  297. relocsec:=objreloc.objsection;
  298. relocval:=objreloc.objsection.mempos
  299. end
  300. else
  301. internalerror(2012060702);
  302. { Only debug sections are allowed to have relocs pointing to unused sections }
  303. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  304. not (oso_debug in objsec.secoptions) then
  305. begin
  306. writeln(objsec.fullname,' references ',relocsec.fullname);
  307. internalerror(2012060703);
  308. end;
  309. PC:=objsec.mempos+objreloc.dataoffset;
  310. { TODO: if relocsec=nil, relocations must be copied to .rel.dyn section }
  311. if (relocsec=nil) or (relocsec.used) then
  312. case reltyp of
  313. R_386_PC32:
  314. begin
  315. if (objreloc.flags and rf_dynamic)<>0 then
  316. WriteDynRelocEntry(PC,R_386_PC32,objreloc.symbol.exesymbol.dynindex,0)
  317. else
  318. address:=address+relocval-PC;
  319. end;
  320. R_386_PLT32:
  321. begin
  322. { If target is in current object, treat as RELOC_RELATIVE }
  323. address:=address+relocval-PC;
  324. end;
  325. R_386_32:
  326. begin
  327. if (objreloc.flags and rf_dynamic)<>0 then
  328. begin
  329. if (objreloc.symbol=nil) or
  330. (objreloc.symbol.exesymbol=nil) or
  331. (objreloc.symbol.exesymbol.dynindex=0) then
  332. begin
  333. address:=address+relocval;
  334. WriteDynRelocEntry(PC,R_386_RELATIVE,0,address);
  335. end
  336. else
  337. { Don't modify address in this case, as it serves as addend for RTLD }
  338. WriteDynRelocEntry(PC,R_386_32,objreloc.symbol.exesymbol.dynindex,0);
  339. end
  340. else
  341. address:=address+relocval;
  342. end;
  343. R_386_GOTPC:
  344. begin
  345. address:=address+gotsymbol.address-PC;
  346. end;
  347. R_386_GOT32:
  348. begin
  349. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  350. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
  351. address:=address+relocval;
  352. end;
  353. R_386_GOTOFF:
  354. begin
  355. address:=address+relocval-gotsymbol.address;
  356. end;
  357. R_386_TLS_IE:
  358. begin
  359. relocval:=-(tlsseg.MemPos+tlsseg.MemSize-relocval);
  360. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  361. { Resolves to *absolute* offset of GOT slot }
  362. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
  363. address:=address+relocval;
  364. end;
  365. R_386_TLS_LE_32,
  366. R_386_TLS_LE:
  367. begin
  368. if IsSharedLibrary then
  369. begin
  370. {
  371. if reltyp=R_386_TLS_LE_32 then
  372. begin
  373. WriteDynRelocEntry(PC,R_386_TLS_TPOFF32,symbol.exesymbol.dynindex,0);
  374. address:=tlsseg.MemPos-relocval;
  375. end;
  376. else
  377. begin
  378. WriteDynRelocEntry(PC,R_386_TLS_TPOFF,symbol.exesymbol.dynindex,0);
  379. address:=address-tlsseg.MemPos;
  380. end;
  381. }
  382. end
  383. else if (reltyp=R_386_TLS_LE) then
  384. address:=-(tlsseg.MemPos+tlsseg.MemSize-relocval)
  385. else
  386. address:=tlsseg.MemPos+tlsseg.MemSize-relocval;
  387. end;
  388. else
  389. begin
  390. writeln(reltyp);
  391. internalerror(200604014);
  392. end;
  393. end
  394. else { not relocsec.Used }
  395. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  396. data.Seek(objreloc.dataoffset);
  397. data.Write(address,4);
  398. end;
  399. end;
  400. {*****************************************************************************
  401. Initialize
  402. *****************************************************************************}
  403. const
  404. elf_target_i386 : TElfTarget =
  405. (
  406. max_page_size: $1000;
  407. exe_image_base: $8048000;
  408. machine_code: EM_386;
  409. relocs_use_addend: false;
  410. dyn_reloc_codes: (
  411. R_386_RELATIVE,
  412. R_386_GLOB_DAT,
  413. R_386_JUMP_SLOT,
  414. R_386_COPY,
  415. R_386_IRELATIVE
  416. );
  417. relocname: @elf_i386_relocName;
  418. encodereloc: @elf_i386_encodeReloc;
  419. loadreloc: @elf_i386_loadReloc;
  420. loadsection: nil;
  421. );
  422. as_i386_elf32_info : tasminfo =
  423. (
  424. id : as_i386_elf32;
  425. idtxt : 'ELF';
  426. asmbin : '';
  427. asmcmd : '';
  428. supported_targets : [system_i386_linux,system_i386_beos,
  429. system_i386_freebsd,system_i386_haiku,
  430. system_i386_openbsd,system_i386_netbsd,
  431. system_i386_Netware,system_i386_netwlibc,
  432. system_i386_solaris,system_i386_embedded];
  433. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
  434. labelprefix : '.L';
  435. comment : '';
  436. dollarsign: '$';
  437. );
  438. initialization
  439. RegisterAssembler(as_i386_elf32_info,TElfAssembler);
  440. ElfExeOutputClass:=TElfExeOutput386;
  441. ElfTarget:=elf_target_i386;
  442. end.