cpuelf.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968
  1. {
  2. Copyright (c) 2012 by Sergei Gorelkin
  3. Includes ELF-related code specific to MIPS
  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. interface
  19. {$i fpcdefs.inc}
  20. implementation
  21. uses
  22. globtype,sysutils,cutils,cclasses,
  23. verbose, elfbase,
  24. systems,aasmbase,ogbase,ogelf,assemble;
  25. type
  26. TElfExeOutputMIPS=class(TElfExeOutput)
  27. private
  28. gpdispsym: TObjSymbol;
  29. gnugpsym: TObjSymbol;
  30. dt_gotsym_value: longint;
  31. dt_local_gotno_value: longint;
  32. dt_local_gotno_offset: aword;
  33. local_got_relocs: TFPObjectList;
  34. local_got_slots: TFPHashObjectList;
  35. got_content: array of pint;
  36. pic_stub_syms: TFPObjectList;
  37. pic_stubs: THashSet;
  38. nullstub: TObjSymbol;
  39. stubcount: longint;
  40. trampolinesection: TObjSection;
  41. procedure MaybeWriteGOTEntry(relocval:aint;objsym:TObjSymbol);
  42. procedure CreatePICStub(objsym:TObjSymbol);
  43. protected
  44. procedure PrepareGOT;override;
  45. function AllocGOTSlot(objsym:TObjSymbol):boolean;override;
  46. procedure CreateGOTSection;override;
  47. procedure CreatePLT;override;
  48. procedure WriteTargetDynamicTags;override;
  49. // procedure WriteFirstPLTEntry;override;
  50. procedure WritePLTEntry(exesym:TExeSymbol);override;
  51. // procedure WriteIndirectPLTEntry(exesym:TExeSymbol);override;
  52. procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);override;
  53. procedure DoRelocationFixup(objsec:TObjSection);override;
  54. procedure Do_Mempos;override;
  55. public
  56. constructor Create;override;
  57. destructor Destroy;override;
  58. procedure FixupRelocations;override;
  59. end;
  60. const
  61. { ELF header e_flags }
  62. EF_MIPS_NOREORDER = 1;
  63. EF_MIPS_PIC = 2;
  64. EF_MIPS_CPIC = 4;
  65. EF_MIPS_ABI = $0000F000;
  66. E_MIPS_ABI_O32 = $00001000;
  67. E_MIPS_ABI_O64 = $00002000;
  68. E_MIPS_ABI_EABI32 = $00003000;
  69. E_MIPS_ABI_EABI64 = $00004000;
  70. EF_MIPS_ARCH = $F0000000;
  71. E_MIPS_ARCH_1 = $00000000; // -mips1
  72. E_MIPS_ARCH_2 = $10000000;
  73. E_MIPS_ARCH_3 = $20000000;
  74. E_MIPS_ARCH_4 = $30000000;
  75. E_MIPS_ARCH_5 = $40000000;
  76. E_MIPS_ARCH_32 = $50000000; // -mips32
  77. E_MIPS_ARCH_64 = $60000000;
  78. E_MIPS_ARCH_32R2= $70000000; // -mips32r2
  79. E_MIPS_ARCH_64R2= $80000000;
  80. { section types }
  81. SHT_MIPS_LIBLIST = $70000000;
  82. SHT_MIPS_CONFLICT = $70000002;
  83. SHT_MIPS_GPTAB = $70000003;
  84. SHT_MIPS_UCODE = $70000004;
  85. SHT_MIPS_DEBUG = $70000005;
  86. SHT_MIPS_REGINFO = $70000006;
  87. SHT_MIPS_DWARF = $7000001e;
  88. { section flags }
  89. SHF_MIPS_GPREL = $10000000;
  90. { relocations }
  91. R_MIPS_NONE = 0;
  92. R_MIPS_16 = 1;
  93. R_MIPS_32 = 2;
  94. R_MIPS_REL32 = 3;
  95. R_MIPS_26 = 4;
  96. R_MIPS_HI16 = 5;
  97. R_MIPS_LO16 = 6;
  98. R_MIPS_GPREL16 = 7;
  99. R_MIPS_LITERAL = 8;
  100. R_MIPS_GOT16 = 9;
  101. R_MIPS_PC16 = 10;
  102. R_MIPS_CALL16 = 11;
  103. R_MIPS_GPREL32 = 12;
  104. R_MIPS_GOT_HI16 = 21;
  105. R_MIPS_GOT_LO16 = 22;
  106. R_MIPS_CALL_HI16 = 30;
  107. R_MIPS_CALL_LO16 = 31;
  108. R_MIPS_JALR = 37;
  109. R_MIPS_TLS_DTPMOD32 = 38;
  110. R_MIPS_TLS_DTPREL32 = 39;
  111. R_MIPS_TLS_DTPMOD64 = 40;
  112. R_MIPS_TLS_DTPREL64 = 41;
  113. R_MIPS_TLS_GD = 42;
  114. R_MIPS_TLS_LDM = 43;
  115. R_MIPS_TLS_DTPREL_HI16 = 44;
  116. R_MIPS_TLS_DTPREL_LO16 = 45;
  117. R_MIPS_TLS_GOTTPREL = 46;
  118. R_MIPS_TLS_TPREL32 = 47;
  119. R_MIPS_TLS_TPREL64 = 48;
  120. R_MIPS_TLS_TPREL_HI16 = 49;
  121. R_MIPS_TLS_TPREL_LO16 = 50;
  122. { dynamic tags }
  123. DT_MIPS_RLD_VERSION = $70000001;
  124. DT_MIPS_TIME_STAMP = $70000002;
  125. DT_MIPS_ICHECKSUM = $70000003;
  126. DT_MIPS_IVERSION = $70000004;
  127. DT_MIPS_FLAGS = $70000005;
  128. DT_MIPS_BASE_ADDRESS = $70000006;
  129. DT_MIPS_CONFLICT = $70000008;
  130. DT_MIPS_LIBLIST = $70000009;
  131. DT_MIPS_LOCAL_GOTNO = $7000000A;
  132. DT_MIPS_CONFLICTNO = $7000000B;
  133. DT_MIPS_LIBLISTNO = $70000010;
  134. DT_MIPS_SYMTABNO = $70000011;
  135. DT_MIPS_UNREFEXTNO = $70000012;
  136. DT_MIPS_GOTSYM = $70000013;
  137. DT_MIPS_HIPAGENO = $70000014;
  138. DT_MIPS_RLD_MAP = $70000016;
  139. { values of DT_MIPS_FLAGS }
  140. RHF_QUICKSTART = 1;
  141. RHF_NOTPOT = 2;
  142. { TLS layout }
  143. TP_OFFSET = $7000;
  144. DTP_OFFSET = $8000;
  145. type
  146. TElfReginfo=record
  147. ri_gprmask: longword;
  148. ri_cprmask: array[0..3] of longword;
  149. ri_gp_value: longint; // signed
  150. end;
  151. TStubHashKey=record
  152. objsec:TObjSection;
  153. offset:aword;
  154. end;
  155. procedure MaybeSwapElfReginfo(var h:TElfReginfo);
  156. var
  157. i: longint;
  158. begin
  159. if source_info.endian<>target_info.endian then
  160. begin
  161. h.ri_gprmask:=swapendian(h.ri_gprmask);
  162. for i:=0 to 3 do
  163. h.ri_cprmask[i]:=swapendian(h.ri_cprmask[i]);
  164. h.ri_gp_value:=swapendian(h.ri_gp_value);
  165. end;
  166. end;
  167. procedure putword(sec:TObjSection;d:longword);
  168. begin
  169. if source_info.endian<>target_info.endian then
  170. d:=swapendian(d);
  171. sec.write(d,4);
  172. end;
  173. {****************************************************************************
  174. ELF Target methods
  175. ****************************************************************************}
  176. function elf_mips_encodereloc(objrel:TObjRelocation):byte;
  177. begin
  178. case objrel.typ of
  179. RELOC_NONE:
  180. result:=R_MIPS_NONE;
  181. RELOC_ABSOLUTE:
  182. result:=R_MIPS_32;
  183. else
  184. result:=0;
  185. InternalError(2012110602);
  186. end;
  187. end;
  188. function elf_mips_relocname(reltyp:byte):string;
  189. begin
  190. result:='TODO';
  191. end;
  192. procedure elf_mips_loadreloc(objrel:TObjRelocation);
  193. begin
  194. end;
  195. function elf_mips_loadsection(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;
  196. begin
  197. case shdr.sh_type of
  198. SHT_MIPS_REGINFO:
  199. result:=true;
  200. else
  201. writeln('elf_mips_loadsection: ',hexstr(shdr.sh_type,8),' ',objdata.name);
  202. result:=false;
  203. end;
  204. end;
  205. {*****************************************************************************
  206. TElfExeOutputMIPS
  207. *****************************************************************************}
  208. constructor TElfExeOutputMIPS.Create;
  209. begin
  210. inherited Create;
  211. local_got_relocs:=TFPObjectList.Create(False);
  212. pic_stub_syms:=TFPObjectList.Create(False);
  213. pic_stubs:=THashSet.Create(64,True,False);
  214. local_got_slots:=TFPHashObjectList.Create(True);
  215. end;
  216. destructor TElfExeOutputMIPS.Destroy;
  217. begin
  218. local_got_slots.Free;
  219. pic_stub_syms.Free;
  220. pic_stubs.Free;
  221. local_got_relocs.Free;
  222. inherited Destroy;
  223. end;
  224. procedure TElfExeOutputMIPS.CreateGOTSection;
  225. begin
  226. nullstub:=TObjSymbol.Create(internalobjdata.ObjSymbolList,'*null_pic_stub*');
  227. nullstub.bind:=AB_LOCAL;
  228. nullstub.typ:=AT_FUNCTION;
  229. gotobjsec:=TElfObjSection.create_ext(internalObjData,'.got',
  230. SHT_PROGBITS,SHF_ALLOC or SHF_WRITE or SHF_MIPS_GPREL,sizeof(pint),sizeof(pint));
  231. gotobjsec.SecOptions:=[oso_keep];
  232. { gotpltobjsec is what's pointed to by DT_PLTGOT }
  233. { TODO: this is not correct; under some circumstances ld can generate PLTs for MIPS,
  234. using classic model. We'll need to support it, too. }
  235. gotpltobjsec:=TElfObjSection(gotobjsec);
  236. internalObjData.SetSection(gotobjsec);
  237. { TODO: must be an absolute symbol; binutils use linker script to define it }
  238. gotsymbol:=internalObjData.SymbolDefine('_gp',AB_GLOBAL,AT_NONE);
  239. gotsymbol.offset:=$7ff0;
  240. { also define _gp_disp and __gnu_local_gp }
  241. gpdispsym:=internalObjData.SymbolDefine('_gp_disp',AB_GLOBAL,AT_NONE);
  242. gnugpsym:=internalObjData.SymbolDefine('__gnu_local_gp',AB_GLOBAL,AT_NONE);
  243. { reserved entries }
  244. gotobjsec.WriteZeros(sizeof(pint));
  245. putword(gotobjsec,$80000000);
  246. end;
  247. procedure TElfExeOutputMIPS.CreatePLT;
  248. begin
  249. pltobjsec:=TElfObjSection.create_ext(internalObjData,'.plt',
  250. SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,4,16);
  251. pltobjsec.SecOptions:=[oso_keep];
  252. end;
  253. procedure TElfExeOutputMIPS.WriteTargetDynamicTags;
  254. begin
  255. writeDynTag(DT_MIPS_RLD_VERSION,1);
  256. if not IsSharedLibrary then
  257. {writeDynTag(DT_MIPS_RLD_MAP,rldmapsec)};
  258. writeDynTag(DT_MIPS_FLAGS,RHF_NOTPOT);
  259. if IsSharedLibrary then
  260. writeDynTag(DT_MIPS_BASE_ADDRESS,0)
  261. else
  262. writeDynTag(DT_MIPS_BASE_ADDRESS,ElfTarget.exe_image_base);
  263. dt_local_gotno_offset:=dynamicsec.size;
  264. writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value);
  265. writeDynTag(DT_MIPS_SYMTABNO,dynsymlist.count+1);
  266. { ABI says: "Index of first external dynamic symbol not referenced locally" }
  267. { What the hell is this? BFD writes number of output sections(!!),
  268. the values found in actual files do not match even that,
  269. and don't seem to be connected to reality at all... }
  270. //writeDynTag(DT_MIPS_UNREFEXTNO,0);
  271. {Index of first dynamic symbol in GOT }
  272. writeDynTag(DT_MIPS_GOTSYM,dt_gotsym_value+1);
  273. end;
  274. procedure TElfExeOutputMIPS.WritePLTEntry(exesym: TExeSymbol);
  275. begin
  276. end;
  277. function TElfExeOutputMIPS.AllocGOTSlot(objsym:TObjSymbol):boolean;
  278. var
  279. exesym: TExeSymbol;
  280. begin
  281. { MIPS has quite a different way of allocating GOT slots and dynamic relocations }
  282. result:=false;
  283. exesym:=objsym.exesymbol;
  284. if (exesym=nil) then
  285. InternalError(2013030406);
  286. if exesym.GotOffset>0 then
  287. exit;
  288. make_dynamic_if_undefweak(exesym);
  289. if (exesym.dynindex>0) and (exesym.ObjSymbol.ObjSection=nil) then
  290. begin
  291. { External symbols must be located at the end of GOT, here just
  292. mark them for dealing later. }
  293. exesym.GotOffset:=high(aword);
  294. exit;
  295. end;
  296. gotobjsec.alloc(sizeof(pint));
  297. exesym.GotOffset:=gotobjsec.size;
  298. result:=true;
  299. end;
  300. function put_externals_last(p1,p2:pointer):longint;
  301. var
  302. sym1: TExeSymbol absolute p1;
  303. sym2: TExeSymbol absolute p2;
  304. begin
  305. result:=ord(sym1.gotoffset=high(aword))-ord(sym2.gotoffset=high(aword));
  306. end;
  307. function address_ascending(p1,p2:pointer):longint;
  308. var
  309. reloc1: TObjRelocation absolute p1;
  310. reloc2: TObjRelocation absolute p2;
  311. begin
  312. result:=(reloc1.symbol.address+reloc1.orgsize)-(reloc2.symbol.address+reloc2.orgsize);
  313. end;
  314. procedure TElfExeOutputMIPS.PrepareGOT;
  315. var
  316. i: longint;
  317. exesym: TExeSymbol;
  318. exesec: TExeSection;
  319. newsec,objsec:TObjSection;
  320. list:TFPObjectList;
  321. begin
  322. inherited PrepareGOT;
  323. { !! maybe incorrect, where do 'unmapped globals' belong? }
  324. dt_local_gotno_value:=gotobjsec.size div sizeof(pint);
  325. { Insert PIC stubs (slow...) }
  326. if assigned(trampolinesection) then
  327. begin
  328. exesec:=FindExeSection('.text');
  329. exesec.ObjSectionList.Add(trampolinesection);
  330. trampolinesection.ExeSection:=exesec;
  331. trampolinesection.Used:=true;
  332. end;
  333. for i:=0 to pic_stub_syms.count-1 do
  334. begin
  335. exesym:=TExeSymbol(pic_stub_syms[i]);
  336. newsec:=exesym.stubsymbol.objsection;
  337. objsec:=exesym.objsymbol.objsection;
  338. list:=objsec.ExeSection.ObjSectionList;
  339. list.insert(list.IndexOf(objsec),newsec);
  340. newsec.ExeSection:=objsec.ExeSection;
  341. newsec.Used:=true;
  342. end;
  343. if not dynamiclink then
  344. exit;
  345. { make room for first R_MIPS_NONE entry }
  346. if dynrelsize>0 then
  347. begin
  348. dynrelocsec.alloc(dynrelocsec.shentsize);
  349. inc(dynrelsize,dynrelocsec.shentsize);
  350. end;
  351. dynsymlist.sort(@put_externals_last);
  352. { reindex, as sorting could changed the order }
  353. for i:=0 to dynsymlist.count-1 do
  354. TExeSymbol(dynsymlist[i]).dynindex:=i+1;
  355. { find the symbol to be written as DT_GOTSYM }
  356. for i:=dynsymlist.count-1 downto 0 do
  357. begin
  358. exesym:=TExeSymbol(dynsymlist[i]);
  359. if exesym.gotoffset<>high(aword) then
  360. begin
  361. dt_gotsym_value:=i+1;
  362. break;
  363. end;
  364. end;
  365. { actually allocate GOT slots for imported symbols }
  366. for i:=dt_gotsym_value to dynsymlist.count-1 do
  367. begin
  368. exesym:=TExeSymbol(dynsymlist[i]);
  369. gotobjsec.alloc(sizeof(pint));
  370. exesym.GotOffset:=gotobjsec.size;
  371. end;
  372. gotsize:=gotobjsec.size;
  373. end;
  374. procedure TElfExeOutputMIPS.Do_Mempos;
  375. var
  376. i:longint;
  377. objrel:TObjRelocation;
  378. addr,page:aword;
  379. numpages,tmp:longint;
  380. objsym:TObjSymbol;
  381. exesym:TExeSymbol;
  382. got_local_area_start:aword;
  383. begin
  384. inherited Do_Mempos;
  385. { determine required amount of 64k page entries }
  386. local_got_relocs.Sort(@address_ascending);
  387. numpages:=0;
  388. page:=high(aword);
  389. for i:=0 to local_got_relocs.count-1 do
  390. begin
  391. objrel:=TObjRelocation(local_got_relocs[i]);
  392. addr:=objrel.symbol.address+objrel.orgsize;
  393. addr:=addr-smallint(addr);
  394. if (page<>addr shr 16) then
  395. inc(numpages);
  396. page:=addr shr 16;
  397. end;
  398. if (numpages=0) then
  399. exit;
  400. { An additional page may be consumed when we add slots to GOT }
  401. inc(numpages);
  402. { Make space in GOT }
  403. got_local_area_start:=dt_local_gotno_value;
  404. inc(gotsize,numpages*sizeof(pint));
  405. gotobjsec.alloc(numpages*sizeof(pint));
  406. { Redo layout }
  407. inherited Do_Mempos;
  408. { Now assign GOT offsets to local slots }
  409. SetLength(got_content,numpages);
  410. page:=high(aword);
  411. tmp:=-1;
  412. objsym:=nil;
  413. for i:=0 to local_got_relocs.count-1 do
  414. begin
  415. objrel:=TObjRelocation(local_got_relocs[i]);
  416. addr:=objrel.symbol.address+objrel.orgsize;
  417. { the contents of slot }
  418. addr:=addr-smallint(addr);
  419. if (page<>addr) then
  420. begin
  421. Inc(tmp);
  422. if (tmp>=numpages) then
  423. InternalError(2013030402);
  424. { replace relocation symbol with one pointing to GOT slot }
  425. objsym:=TObjSymbol.Create(local_got_slots,hexstr(addr,8));
  426. objsym.offset:=(got_local_area_start+tmp+1)*sizeof(pint);
  427. objsym.bind:=AB_LOCAL;
  428. if (source_info.endian=target_info.endian) then
  429. got_content[tmp]:=addr
  430. else
  431. got_content[tmp]:=swapendian(addr);
  432. page:=addr;
  433. end;
  434. objrel.symbol:=objsym;
  435. end;
  436. if dynamiclink then
  437. begin
  438. { Patch DT_LOCAL_GOTNO value }
  439. if (dt_local_gotno_offset=0) then
  440. InternalError(2013030401);
  441. i:=dynamicsec.size;
  442. dynamicsec.Data.Seek(dt_local_gotno_offset);
  443. writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value+numpages);
  444. dynamicsec.size:=i;
  445. { Increase gotoffset of exesymbols that come after dt_gotsym }
  446. for i:=dt_gotsym_value to dynsymlist.count-1 do
  447. begin
  448. exesym:=TExeSymbol(dynsymlist[i]);
  449. exesym.GotOffset:=exesym.GotOffset+(numpages*sizeof(pint));
  450. end;
  451. end;
  452. end;
  453. procedure TElfExeOutputMIPS.FixupRelocations;
  454. begin
  455. if dynrelsize>0 then
  456. WriteDynRelocEntry(0,R_MIPS_NONE,0,0);
  457. inherited FixupRelocations;
  458. { Since we omit GOT slots for imported symbols during inherited PrepareGOT, they don't
  459. get written in FixupRelocations either. This must be compensated here. }
  460. gotobjsec.write(got_content[0],length(got_content)*sizeof(pint));
  461. { TODO: shouldn't be zeroes, but address of stubs if address taken, etc. }
  462. gotobjsec.writeZeros(gotsize-gotobjsec.size);
  463. end;
  464. procedure TElfExeOutputMIPS.MaybeWriteGOTEntry(relocval:aint;objsym:TObjSymbol);
  465. var
  466. gotoff:aword;
  467. begin
  468. if (objsym.bind=AB_LOCAL) then
  469. InternalError(2013030403);
  470. gotoff:=objsym.exesymbol.gotoffset;
  471. if gotoff=0 then
  472. InternalError(2012060902);
  473. { On MIPS, GOT does not need dynamic relocations }
  474. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  475. begin
  476. if source_info.endian<>target_info.endian then
  477. relocval:=swapendian(relocval);
  478. gotobjsec.write(relocval,sizeof(pint));
  479. end;
  480. end;
  481. procedure TElfExeOutputMIPS.CreatePICStub(objsym:TObjSymbol);
  482. var
  483. textsec,newsec:TObjSection;
  484. newsym:TObjSymbol;
  485. use_trampoline:boolean;
  486. begin
  487. textsec:=objsym.objsection;
  488. use_trampoline:=(objsym.offset>0) or (textsec.SecAlign>16);
  489. if use_trampoline then
  490. begin
  491. if trampolinesection=nil then
  492. trampolinesection:=internalObjData.createsection(sec_code);
  493. newsec:=trampolinesection;
  494. end
  495. else
  496. begin
  497. inc(stubcount);
  498. newsec:=TElfObjSection.create_ext(internalObjData,'.text.stub.'+tostr(stubcount),
  499. SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,0,textsec.SecAlign);
  500. if (newsec.SecAlign>8) then
  501. newsec.WriteZeros(newsec.SecAlign-8);
  502. pic_stub_syms.add(objsym.ExeSymbol);
  503. end;
  504. { symbol for the stub }
  505. internalObjData.SetSection(newsec);
  506. newsym:=internalObjData.symboldefine('.pic.'+objsym.name,AB_LOCAL,AT_FUNCTION);
  507. putword(newsec,$3c190000); // lui $t9,%hi(x)
  508. newsec.addrawreloc(newsec.size-4,objsym,R_MIPS_HI16);
  509. if use_trampoline then
  510. begin
  511. putword(newsec,$08000000); // j x
  512. newsec.addrawreloc(newsec.size-4,objsym,R_MIPS_26);
  513. end;
  514. putword(newsec,$27390000); // addiu $t9,$t9,%lo(x)
  515. newsec.addrawreloc(newsec.size-4,objsym,R_MIPS_LO16);
  516. objsym.exesymbol.stubsymbol:=newsym;
  517. end;
  518. procedure TElfExeOutputMIPS.GOTRelocPass1(objsec:TObjSection;var idx:longint);
  519. var
  520. objreloc:TObjRelocation;
  521. lowreloc:TObjRelocation;
  522. reltyp:byte;
  523. externsym:boolean;
  524. found:boolean;
  525. i:longint;
  526. lopart,hipart:longword;
  527. objdata:TElfObjData;
  528. exesym:TExeSymbol;
  529. targetsec:TObjSection;
  530. tmp:array[0..2] of longword;
  531. key:TStubHashKey;
  532. entry:PHashSetItem;
  533. begin
  534. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  535. if (ObjReloc.flags and rf_raw)=0 then
  536. reltyp:=ElfTarget.encodereloc(ObjReloc)
  537. else
  538. reltyp:=ObjReloc.ftype;
  539. case reltyp of
  540. R_MIPS_32:
  541. begin
  542. externsym:=assigned(objreloc.symbol) and
  543. assigned(objreloc.symbol.exesymbol) and
  544. (objreloc.symbol.exesymbol.dynindex<>0);
  545. if IsSharedLibrary then
  546. begin
  547. dynrelocsec.alloc(dynrelocsec.shentsize);
  548. objreloc.flags:=objreloc.flags or rf_dynamic;
  549. if (not externsym) then
  550. Inc(relative_reloc_count);
  551. end
  552. end;
  553. R_MIPS_PC16,
  554. R_MIPS_26:
  555. begin
  556. { Absolute calls into PIC code must go through stubs that load R25 }
  557. exesym:=objreloc.symbol.exesymbol;
  558. if (exesym=nil) or (exesym.dynindex<>0) then
  559. exit;
  560. { Stub already created? Redirect to it and be done. }
  561. if assigned(exesym.stubsymbol) then
  562. begin
  563. if (exesym.stubsymbol<>nullstub) then
  564. begin
  565. objreloc.symbol.offset:=exesym.stubsymbol.offset;
  566. objreloc.symbol.objsection:=exesym.stubsymbol.objsection;
  567. end;
  568. exit;
  569. end;
  570. targetsec:=exesym.ObjSymbol.objsection;
  571. objdata:=TElfObjData(targetsec.ObjData);
  572. if (objdata.flags and EF_MIPS_PIC)=0 then
  573. exit;
  574. { Same objdata? then it's responsibility of assembler, not linker }
  575. if (objdata=objsec.objdata) then
  576. exit;
  577. { Check if destination begins with PIC prologue. If not, mark symbol
  578. with 'null' stub so we don't waste time on subsequent relocs to it. }
  579. targetsec.data.seek(exesym.ObjSymbol.offset);
  580. targetsec.data.read(tmp,3*sizeof(longword));
  581. if (source_info.endian<>target_info.endian) then
  582. for i:=0 to 2 do
  583. tmp[i]:=swapendian(tmp[i]);
  584. if ((tmp[0] and $FFFF0000)<>$3C1C0000) or
  585. ((tmp[1] and $FFFF0000)<>$279C0000) or
  586. (tmp[2]<>$0399E021) then
  587. begin
  588. exesym.stubsymbol:=nullstub;
  589. exit;
  590. end;
  591. { Avoid creating several stubs for an address due to symbol aliasing }
  592. key.objsec:=targetsec;
  593. key.offset:=exesym.ObjSymbol.offset;
  594. entry:=pic_stubs.FindOrAdd(@key,sizeof(TStubHashKey));
  595. if assigned(entry^.Data) then
  596. exesym:=TExeSymbol(entry^.Data)
  597. else
  598. begin
  599. entry^.Data:=exesym;
  600. CreatePICStub(exesym.objsymbol);
  601. end;
  602. objreloc.symbol.offset:=exesym.stubsymbol.offset;
  603. objreloc.symbol.objsection:=exesym.stubsymbol.objsection;
  604. end;
  605. R_MIPS_CALL16,
  606. R_MIPS_GOT16:
  607. begin
  608. if objreloc.symbol.bind<>AB_LOCAL then
  609. AllocGOTSlot(objreloc.symbol)
  610. else
  611. begin
  612. { Extract the addend, which is stored split between this relocation and
  613. the following (maybe not immediately) R_MIPS_LO16 one. }
  614. found:=false;
  615. for i:=idx+1 to objsec.ObjRelocations.Count-1 do
  616. begin
  617. lowreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  618. if (lowreloc.flags and rf_raw)=0 then
  619. InternalError(2013030101);
  620. if (lowreloc.ftype=R_MIPS_LO16) then
  621. begin;
  622. found:=true;
  623. break;
  624. end;
  625. end;
  626. if not found then
  627. InternalError(2013030102);
  628. objsec.Data.Seek(objreloc.DataOffset);
  629. objsec.Data.Read(hipart,sizeof(hipart));
  630. objsec.Data.Seek(lowreloc.DataOffset);
  631. objsec.Data.Read(lopart,sizeof(lopart));
  632. if (source_info.endian<>target_info.endian) then
  633. begin
  634. hipart:=swapendian(hipart);
  635. lopart:=swapendian(lopart);
  636. end;
  637. objreloc.orgsize:=(hipart shl 16)+SmallInt(lopart);
  638. local_got_relocs.add(objreloc);
  639. end;
  640. end;
  641. end;
  642. end;
  643. type
  644. PRelocData=^TRelocData;
  645. TRelocData=record
  646. next:PRelocData;
  647. objsec:TObjSection;
  648. objrel:TObjRelocation;
  649. addend:aint;
  650. end;
  651. procedure TElfExeOutputMIPS.DoRelocationFixup(objsec:TObjSection);
  652. var
  653. i,zero:longint;
  654. objreloc: TObjRelocation;
  655. AHL_S,
  656. tmp,
  657. address,
  658. relocval : aint;
  659. relocsec : TObjSection;
  660. data: TDynamicArray;
  661. reltyp: byte;
  662. curloc: aword;
  663. reloclist,hr: PRelocData;
  664. is_gp_disp: boolean;
  665. begin
  666. data:=objsec.data;
  667. reloclist:=nil;
  668. for i:=0 to objsec.ObjRelocations.Count-1 do
  669. begin
  670. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  671. case objreloc.typ of
  672. RELOC_NONE:
  673. continue;
  674. RELOC_ZERO:
  675. begin
  676. data.Seek(objreloc.dataoffset);
  677. zero:=0;
  678. data.Write(zero,4);
  679. continue;
  680. end;
  681. end;
  682. if (objreloc.flags and rf_raw)=0 then
  683. reltyp:=ElfTarget.encodereloc(objreloc)
  684. else
  685. reltyp:=objreloc.ftype;
  686. if ElfTarget.relocs_use_addend then
  687. address:=objreloc.orgsize
  688. else
  689. begin
  690. data.Seek(objreloc.dataoffset);
  691. data.Read(address,4);
  692. if source_info.endian<>target_info.endian then
  693. address:=swapendian(address);
  694. end;
  695. if assigned(objreloc.symbol) then
  696. begin
  697. relocsec:=objreloc.symbol.objsection;
  698. relocval:=objreloc.symbol.address;
  699. end
  700. else if assigned(objreloc.objsection) then
  701. begin
  702. relocsec:=objreloc.objsection;
  703. relocval:=objreloc.objsection.mempos
  704. end
  705. else
  706. internalerror(2012060702);
  707. { Only debug sections are allowed to have relocs pointing to unused sections }
  708. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  709. not (oso_debug in objsec.secoptions) then
  710. begin
  711. writeln(objsec.fullname,' references ',relocsec.fullname);
  712. internalerror(2012060703);
  713. end;
  714. curloc:=objsec.mempos+objreloc.dataoffset;
  715. if (relocsec=nil) or (relocsec.used) then
  716. case reltyp of
  717. R_MIPS_32:
  718. begin
  719. address:=address+relocval;
  720. if (objreloc.flags and rf_dynamic)<>0 then
  721. begin
  722. if (objreloc.symbol=nil) or
  723. (objreloc.symbol.exesymbol=nil) or
  724. (objreloc.symbol.exesymbol.dynindex=0) then
  725. WriteDynRelocEntry(curloc,R_MIPS_REL32,0,address)
  726. else
  727. dynreloclist.add(TObjRelocation.CreateRaw(curloc,objreloc.symbol,R_MIPS_REL32));
  728. end;
  729. end;
  730. R_MIPS_26:
  731. begin
  732. tmp:=(address and $03FFFFFF) shl 2;
  733. tmp:=((tmp or (curloc and $F0000000))+relocval) shr 2;
  734. address:=(address and $FC000000) or (tmp and $3FFFFFF);
  735. end;
  736. R_MIPS_HI16:
  737. begin
  738. { This relocation can be handled only after seeing a matching LO16 one,
  739. moreover BFD supports any number of HI16 to precede a single LO16.
  740. So just add it to a queue. }
  741. new(hr);
  742. hr^.next:=reloclist;
  743. hr^.objrel:=objreloc;
  744. hr^.objsec:=objsec;
  745. hr^.addend:=address; //TODO: maybe it can be saved in objrel.orgsize field
  746. reloclist:=hr;
  747. end;
  748. R_MIPS_LO16:
  749. begin
  750. { LO16 may be without pair, e.g. in following sequence:
  751. lui $v0, %hi(foo)
  752. lw $a0, %lo(foo)($v0)
  753. lw $a1, %lo(foo+4)($v0)
  754. }
  755. AHL_S:=SmallInt(address)+relocval;
  756. is_gp_disp:=false;
  757. while assigned(reloclist) do
  758. begin
  759. hr:=reloclist;
  760. reloclist:=hr^.next;
  761. // if relocval<>hr^.relocval then // must be the same symbol
  762. // InternalError();
  763. { _gp_disp and __gnu_local_gp magic }
  764. if assigned(hr^.objrel.symbol) and
  765. (hr^.objrel.symbol.bind<>AB_LOCAL) then
  766. begin
  767. is_gp_disp:=(hr^.objrel.symbol.exesymbol.objsymbol=gpdispsym);
  768. if (hr^.objrel.symbol.exesymbol.objsymbol=gnugpsym) then
  769. relocval:=gotsymbol.address;
  770. end;
  771. { in case of _gp_disp, non-zero addend is not possible? }
  772. { 4 must be added right here, so possible overflow in low half
  773. is propagated into high one (e.g if displacement is $37ffc,
  774. high part must be 4, not 3) }
  775. if is_gp_disp then
  776. relocval:=gotsymbol.address-curloc+4;
  777. AHL_S:=(hr^.addend shl 16)+SmallInt(address)+relocval;
  778. case hr^.objrel.ftype of
  779. R_MIPS_HI16:
  780. tmp:=(AHL_S-SmallInt(AHL_S)) shr 16;
  781. R_MIPS_GOT16:
  782. tmp:=-(gotsymbol.offset-(hr^.objrel.symbol.offset-sizeof(pint)));
  783. else
  784. InternalError(2013030404);
  785. end;
  786. tmp:=(hr^.addend and $FFFF0000) or (tmp and $FFFF);
  787. data.seek(hr^.objrel.dataoffset);
  788. if source_info.endian<>target_info.endian then
  789. tmp:=swapendian(tmp);
  790. data.Write(tmp,4);
  791. dispose(hr);
  792. end;
  793. address:=(address and $FFFF0000) or (AHL_S and $FFFF);
  794. end;
  795. R_MIPS_CALL16,
  796. R_MIPS_GOT16:
  797. begin
  798. { GOT16 relocations against local symbols are followed by LO16 }
  799. if (objreloc.symbol.bind=AB_LOCAL) then
  800. begin
  801. new(hr);
  802. hr^.next:=reloclist;
  803. hr^.objrel:=objreloc;
  804. hr^.objsec:=objsec;
  805. hr^.addend:=address; //TODO: maybe it can be saved in objrel.orgsize field
  806. reloclist:=hr;
  807. continue;
  808. end;
  809. MaybeWriteGOTEntry(relocval,objreloc.symbol);
  810. // !! this is correct only while _gp symbol is defined relative to .got !!
  811. relocval:=-(gotsymbol.offset-(objreloc.symbol.exesymbol.gotoffset-sizeof(pint)));
  812. // TODO: check overflow
  813. address:=(address and $FFFF0000) or (relocval and $FFFF);
  814. end;
  815. R_MIPS_PC16:
  816. //TODO: check overflow
  817. address:=(address and $FFFF0000) or ((((SmallInt(address) shl 2)+relocval-curloc) shr 2) and $FFFF);
  818. R_MIPS_JALR: {optimization hint, ignore for now }
  819. ;
  820. else
  821. begin
  822. writeln(objsec.fullname,'+',objreloc.dataoffset,' ',objreloc.ftype);
  823. internalerror(200604014);
  824. end;
  825. end
  826. else { not relocsec.Used }
  827. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  828. data.Seek(objreloc.dataoffset);
  829. if source_info.endian<>target_info.endian then
  830. address:=swapendian(address);
  831. data.Write(address,4);
  832. end;
  833. end;
  834. {*****************************************************************************
  835. Initialize
  836. *****************************************************************************}
  837. const
  838. elf_target_mips: TElfTarget =
  839. (
  840. max_page_size: $10000;
  841. exe_image_base: $400000;
  842. machine_code: EM_MIPS;
  843. relocs_use_addend: false;
  844. dyn_reloc_codes: (
  845. 0,
  846. 0,
  847. 0,
  848. 0,
  849. 0
  850. );
  851. relocname: @elf_mips_relocName;
  852. encodereloc: @elf_mips_encodeReloc;
  853. loadreloc: @elf_mips_loadReloc;
  854. loadsection: @elf_mips_loadSection;
  855. );
  856. initialization
  857. ElfTarget:=elf_target_mips;
  858. ElfExeOutputClass:=TElfExeOutputMIPS;
  859. end.