cpuelf.pas 36 KB

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