cpuelf.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  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. procedure MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  37. protected
  38. procedure PrepareGOT;override;
  39. function AllocGOTSlot(objsym:TObjSymbol):boolean;override;
  40. procedure CreateGOTSection;override;
  41. procedure CreatePLT;override;
  42. procedure WriteTargetDynamicTags;override;
  43. // procedure WriteFirstPLTEntry;override;
  44. procedure WritePLTEntry(exesym:TExeSymbol);override;
  45. // procedure WriteIndirectPLTEntry(exesym:TExeSymbol);override;
  46. procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);override;
  47. procedure DoRelocationFixup(objsec:TObjSection);override;
  48. procedure Do_Mempos;override;
  49. public
  50. constructor Create;override;
  51. destructor Destroy;override;
  52. procedure FixupRelocations;override;
  53. end;
  54. const
  55. { section types }
  56. SHT_MIPS_LIBLIST = $70000000;
  57. SHT_MIPS_CONFLICT = $70000002;
  58. SHT_MIPS_GPTAB = $70000003;
  59. SHT_MIPS_UCODE = $70000004;
  60. SHT_MIPS_DEBUG = $70000005;
  61. SHT_MIPS_REGINFO = $70000006;
  62. { section flags }
  63. SHF_MIPS_GPREL = $10000000;
  64. { relocations }
  65. R_MIPS_NONE = 0;
  66. R_MIPS_16 = 1;
  67. R_MIPS_32 = 2;
  68. R_MIPS_REL32 = 3;
  69. R_MIPS_26 = 4;
  70. R_MIPS_HI16 = 5;
  71. R_MIPS_LO16 = 6;
  72. R_MIPS_GPREL16 = 7;
  73. R_MIPS_LITERAL = 8;
  74. R_MIPS_GOT16 = 9;
  75. R_MIPS_PC16 = 10;
  76. R_MIPS_CALL16 = 11;
  77. R_MIPS_GPREL32 = 12;
  78. R_MIPS_GOT_HI16 = 21;
  79. R_MIPS_GOT_LO16 = 22;
  80. R_MIPS_CALL_HI16 = 30;
  81. R_MIPS_CALL_LO16 = 31;
  82. R_MIPS_JALR = 37;
  83. { dynamic tags }
  84. DT_MIPS_RLD_VERSION = $70000001;
  85. DT_MIPS_TIME_STAMP = $70000002;
  86. DT_MIPS_ICHECKSUM = $70000003;
  87. DT_MIPS_IVERSION = $70000004;
  88. DT_MIPS_FLAGS = $70000005;
  89. DT_MIPS_BASE_ADDRESS = $70000006;
  90. DT_MIPS_CONFLICT = $70000008;
  91. DT_MIPS_LIBLIST = $70000009;
  92. DT_MIPS_LOCAL_GOTNO = $7000000A;
  93. DT_MIPS_CONFLICTNO = $7000000B;
  94. DT_MIPS_LIBLISTNO = $70000010;
  95. DT_MIPS_SYMTABNO = $70000011;
  96. DT_MIPS_UNREFEXTNO = $70000012;
  97. DT_MIPS_GOTSYM = $70000013;
  98. DT_MIPS_HIPAGENO = $70000014;
  99. DT_MIPS_RLD_MAP = $70000016;
  100. { values of DT_MIPS_FLAGS }
  101. RHF_QUICKSTART = 1;
  102. RHF_NOTPOT = 2;
  103. type
  104. TElfReginfo=record
  105. ri_gprmask: longword;
  106. ri_cprmask: array[0..3] of longword;
  107. ri_gp_value: longint; // signed
  108. end;
  109. procedure MaybeSwapElfReginfo(var h:TElfReginfo);
  110. var
  111. i: longint;
  112. begin
  113. if source_info.endian<>target_info.endian then
  114. begin
  115. h.ri_gprmask:=swapendian(h.ri_gprmask);
  116. for i:=0 to 3 do
  117. h.ri_cprmask[i]:=swapendian(h.ri_cprmask[i]);
  118. h.ri_gp_value:=swapendian(h.ri_gp_value);
  119. end;
  120. end;
  121. {****************************************************************************
  122. ELF Target methods
  123. ****************************************************************************}
  124. function elf_mips_encodereloc(objrel:TObjRelocation):byte;
  125. begin
  126. case objrel.typ of
  127. RELOC_NONE:
  128. result:=R_MIPS_NONE;
  129. RELOC_ABSOLUTE:
  130. result:=R_MIPS_32;
  131. else
  132. result:=0;
  133. InternalError(2012110602);
  134. end;
  135. end;
  136. function elf_mips_relocname(reltyp:byte):string;
  137. begin
  138. result:='TODO';
  139. end;
  140. procedure elf_mips_loadreloc(objrel:TObjRelocation);
  141. begin
  142. end;
  143. function elf_mips_loadsection(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;
  144. begin
  145. case shdr.sh_type of
  146. SHT_MIPS_REGINFO:
  147. result:=true;
  148. else
  149. writeln('elf_mips_loadsection: ',hexstr(shdr.sh_type,8),' ',objdata.name);
  150. result:=false;
  151. end;
  152. end;
  153. {*****************************************************************************
  154. TElfExeOutputMIPS
  155. *****************************************************************************}
  156. constructor TElfExeOutputMIPS.Create;
  157. begin
  158. inherited Create;
  159. local_got_relocs:=TFPObjectList.Create(False);
  160. local_got_slots:=TFPHashObjectList.Create(True);
  161. end;
  162. destructor TElfExeOutputMIPS.Destroy;
  163. begin
  164. local_got_slots.Free;
  165. local_got_relocs.Free;
  166. inherited Destroy;
  167. end;
  168. procedure TElfExeOutputMIPS.CreateGOTSection;
  169. var
  170. tmp: longword;
  171. begin
  172. gotobjsec:=TElfObjSection.create_ext(internalObjData,'.got',
  173. SHT_PROGBITS,SHF_ALLOC or SHF_WRITE or SHF_MIPS_GPREL,sizeof(pint),sizeof(pint));
  174. gotobjsec.SecOptions:=[oso_keep];
  175. { gotpltobjsec is what's pointed to by DT_PLTGOT }
  176. { TODO: this is not correct; under some circumstances ld can generate PLTs for MIPS,
  177. using classic model. We'll need to support it, too. }
  178. gotpltobjsec:=TElfObjSection(gotobjsec);
  179. internalObjData.SetSection(gotobjsec);
  180. { TODO: must be an absolute symbol; binutils use linker script to define it }
  181. gotsymbol:=internalObjData.SymbolDefine('_gp',AB_GLOBAL,AT_NONE);
  182. gotsymbol.offset:=$7ff0;
  183. { also define _gp_disp and __gnu_local_gp }
  184. gpdispsym:=internalObjData.SymbolDefine('_gp_disp',AB_GLOBAL,AT_NONE);
  185. gnugpsym:=internalObjData.SymbolDefine('__gnu_local_gp',AB_GLOBAL,AT_NONE);
  186. { reserved entries }
  187. gotobjsec.WriteZeros(sizeof(pint));
  188. tmp:=$80000000;
  189. if target_info.endian<>source_info.endian then
  190. tmp:=swapendian(tmp);
  191. gotobjsec.Write(tmp,sizeof(pint));
  192. end;
  193. procedure TElfExeOutputMIPS.CreatePLT;
  194. begin
  195. pltobjsec:=TElfObjSection.create_ext(internalObjData,'.plt',
  196. SHT_PROGBITS,SHF_ALLOC or SHF_EXECINSTR,4,16);
  197. pltobjsec.SecOptions:=[oso_keep];
  198. end;
  199. procedure TElfExeOutputMIPS.WriteTargetDynamicTags;
  200. begin
  201. writeDynTag(DT_MIPS_RLD_VERSION,1);
  202. if not IsSharedLibrary then
  203. {writeDynTag(DT_MIPS_RLD_MAP,rldmapsec)};
  204. writeDynTag(DT_MIPS_FLAGS,RHF_NOTPOT);
  205. if IsSharedLibrary then
  206. writeDynTag(DT_MIPS_BASE_ADDRESS,0)
  207. else
  208. writeDynTag(DT_MIPS_BASE_ADDRESS,ElfTarget.exe_image_base);
  209. dt_local_gotno_offset:=dynamicsec.size;
  210. writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value);
  211. writeDynTag(DT_MIPS_SYMTABNO,dynsymlist.count+1);
  212. { ABI says: "Index of first external dynamic symbol not referenced locally" }
  213. { What the hell is this? BFD writes number of output sections(!!),
  214. the values found in actual files do not match even that,
  215. and don't seem to be connected to reality at all... }
  216. //writeDynTag(DT_MIPS_UNREFEXTNO,0);
  217. {Index of first dynamic symbol in GOT }
  218. writeDynTag(DT_MIPS_GOTSYM,dt_gotsym_value+1);
  219. end;
  220. procedure TElfExeOutputMIPS.WritePLTEntry(exesym: TExeSymbol);
  221. begin
  222. end;
  223. function TElfExeOutputMIPS.AllocGOTSlot(objsym:TObjSymbol):boolean;
  224. var
  225. exesym: TExeSymbol;
  226. begin
  227. { MIPS has quite a different way of allocating GOT slots and dynamic relocations }
  228. result:=false;
  229. exesym:=objsym.exesymbol;
  230. if (exesym=nil) then
  231. InternalError(2013030406);
  232. if exesym.GotOffset>0 then
  233. exit;
  234. make_dynamic_if_undefweak(exesym);
  235. if (exesym.dynindex>0) and (exesym.ObjSymbol.ObjSection=nil) then
  236. begin
  237. { External symbols must be located at the end of GOT, here just
  238. mark them for dealing later. }
  239. exesym.GotOffset:=high(aword);
  240. exit;
  241. end;
  242. gotobjsec.alloc(sizeof(pint));
  243. exesym.GotOffset:=gotobjsec.size;
  244. result:=true;
  245. end;
  246. function put_externals_last(p1,p2:pointer):longint;
  247. var
  248. sym1: TExeSymbol absolute p1;
  249. sym2: TExeSymbol absolute p2;
  250. begin
  251. result:=ord(sym1.gotoffset=high(aword))-ord(sym2.gotoffset=high(aword));
  252. end;
  253. function address_ascending(p1,p2:pointer):longint;
  254. var
  255. reloc1: TObjRelocation absolute p1;
  256. reloc2: TObjRelocation absolute p2;
  257. begin
  258. result:=(reloc1.symbol.address+reloc1.orgsize)-(reloc2.symbol.address+reloc2.orgsize);
  259. end;
  260. procedure TElfExeOutputMIPS.PrepareGOT;
  261. var
  262. i: longint;
  263. exesym: TExeSymbol;
  264. begin
  265. inherited PrepareGOT;
  266. { !! maybe incorrect, where do 'unmapped globals' belong? }
  267. dt_local_gotno_value:=gotobjsec.size div sizeof(pint);
  268. if not dynamiclink then
  269. exit;
  270. { make room for first R_MIPS_NONE entry }
  271. if dynrelsize>0 then
  272. begin
  273. dynrelocsec.alloc(dynrelocsec.shentsize);
  274. inc(dynrelsize,dynrelocsec.shentsize);
  275. end;
  276. dynsymlist.sort(@put_externals_last);
  277. { reindex, as sorting could changed the order }
  278. for i:=0 to dynsymlist.count-1 do
  279. TExeSymbol(dynsymlist[i]).dynindex:=i+1;
  280. { find the symbol to be written as DT_GOTSYM }
  281. for i:=dynsymlist.count-1 downto 0 do
  282. begin
  283. exesym:=TExeSymbol(dynsymlist[i]);
  284. if exesym.gotoffset<>high(aword) then
  285. begin
  286. dt_gotsym_value:=i+1;
  287. break;
  288. end;
  289. end;
  290. { actually allocate GOT slots for imported symbols }
  291. for i:=dt_gotsym_value to dynsymlist.count-1 do
  292. begin
  293. exesym:=TExeSymbol(dynsymlist[i]);
  294. gotobjsec.alloc(sizeof(pint));
  295. exesym.GotOffset:=gotobjsec.size;
  296. end;
  297. gotsize:=gotobjsec.size;
  298. end;
  299. procedure TElfExeOutputMIPS.Do_Mempos;
  300. var
  301. i:longint;
  302. objrel:TObjRelocation;
  303. addr,page:aword;
  304. numpages,tmp:longint;
  305. objsym:TObjSymbol;
  306. exesym:TExeSymbol;
  307. got_local_area_start:aword;
  308. begin
  309. inherited Do_Mempos;
  310. { determine required amount of 64k page entries }
  311. local_got_relocs.Sort(@address_ascending);
  312. numpages:=0;
  313. page:=high(aword);
  314. for i:=0 to local_got_relocs.count-1 do
  315. begin
  316. objrel:=TObjRelocation(local_got_relocs[i]);
  317. addr:=objrel.symbol.address+objrel.orgsize;
  318. addr:=addr-smallint(addr);
  319. if (page<>addr shr 16) then
  320. inc(numpages);
  321. page:=addr shr 16;
  322. end;
  323. if (numpages=0) then
  324. exit;
  325. { An additional page may be consumed when we add slots to GOT }
  326. inc(numpages);
  327. { Make space in GOT }
  328. got_local_area_start:=dt_local_gotno_value;
  329. inc(gotsize,numpages*sizeof(pint));
  330. gotobjsec.alloc(numpages*sizeof(pint));
  331. { Redo layout }
  332. inherited Do_Mempos;
  333. { Now assign GOT offsets to local slots }
  334. SetLength(got_content,numpages);
  335. page:=high(aword);
  336. tmp:=-1;
  337. objsym:=nil;
  338. for i:=0 to local_got_relocs.count-1 do
  339. begin
  340. objrel:=TObjRelocation(local_got_relocs[i]);
  341. addr:=objrel.symbol.address+objrel.orgsize;
  342. { the contents of slot }
  343. addr:=addr-smallint(addr);
  344. if (page<>addr) then
  345. begin
  346. Inc(tmp);
  347. if (tmp>=numpages) then
  348. InternalError(2013030402);
  349. { replace relocation symbol with one pointing to GOT slot }
  350. objsym:=TObjSymbol.Create(local_got_slots,hexstr(addr,8));
  351. objsym.offset:=(got_local_area_start+tmp+1)*sizeof(pint);
  352. objsym.bind:=AB_LOCAL;
  353. if (source_info.endian=target_info.endian) then
  354. got_content[tmp]:=addr
  355. else
  356. got_content[tmp]:=swapendian(addr);
  357. page:=addr;
  358. end;
  359. objrel.symbol:=objsym;
  360. end;
  361. if dynamiclink then
  362. begin
  363. { Patch DT_LOCAL_GOTNO value }
  364. if (dt_local_gotno_offset=0) then
  365. InternalError(2013030401);
  366. i:=dynamicsec.size;
  367. dynamicsec.Data.Seek(dt_local_gotno_offset);
  368. writeDynTag(DT_MIPS_LOCAL_GOTNO,dt_local_gotno_value+numpages);
  369. dynamicsec.size:=i;
  370. { Increase gotoffset of exesymbols that come after dt_gotsym }
  371. for i:=dt_gotsym_value to dynsymlist.count-1 do
  372. begin
  373. exesym:=TExeSymbol(dynsymlist[i]);
  374. exesym.GotOffset:=exesym.GotOffset+(numpages*sizeof(pint));
  375. end;
  376. end;
  377. end;
  378. procedure TElfExeOutputMIPS.FixupRelocations;
  379. begin
  380. if dynrelsize>0 then
  381. WriteDynRelocEntry(0,R_MIPS_NONE,0,0);
  382. inherited FixupRelocations;
  383. { Since we omit GOT slots for imported symbols during inherited PrepareGOT, they don't
  384. get written in FixupRelocations either. This must be compensated here. }
  385. gotobjsec.write(got_content[0],length(got_content)*sizeof(pint));
  386. { TODO: shouldn't be zeroes, but address of stubs if address taken, etc. }
  387. gotobjsec.writeZeros(gotsize-gotobjsec.size);
  388. end;
  389. procedure TElfExeOutputMIPS.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  390. var
  391. gotoff:aword;
  392. begin
  393. if (objsym.bind=AB_LOCAL) then
  394. InternalError(2013030403);
  395. gotoff:=objsym.exesymbol.gotoffset;
  396. if gotoff=0 then
  397. InternalError(2012060902);
  398. { On MIPS, GOT does not need dynamic relocations }
  399. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  400. begin
  401. if source_info.endian<>target_info.endian then
  402. relocval:=swapendian(relocval);
  403. gotobjsec.write(relocval,sizeof(pint));
  404. end;
  405. end;
  406. procedure TElfExeOutputMIPS.GOTRelocPass1(objsec:TObjSection;var idx:longint);
  407. var
  408. objreloc:TObjRelocation;
  409. lowreloc:TObjRelocation;
  410. reltyp:byte;
  411. externsym:boolean;
  412. found:boolean;
  413. i:longint;
  414. lopart,hipart:longword;
  415. begin
  416. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  417. if (ObjReloc.flags and rf_raw)=0 then
  418. reltyp:=ElfTarget.encodereloc(ObjReloc)
  419. else
  420. reltyp:=ObjReloc.ftype;
  421. case reltyp of
  422. R_MIPS_32:
  423. begin
  424. externsym:=assigned(objreloc.symbol) and
  425. assigned(objreloc.symbol.exesymbol) and
  426. (objreloc.symbol.exesymbol.dynindex<>0);
  427. if IsSharedLibrary then
  428. begin
  429. dynrelocsec.alloc(dynrelocsec.shentsize);
  430. objreloc.flags:=objreloc.flags or rf_dynamic;
  431. if (not externsym) then
  432. Inc(relative_reloc_count);
  433. end
  434. end;
  435. R_MIPS_CALL16,
  436. R_MIPS_GOT16:
  437. begin
  438. if objreloc.symbol.bind<>AB_LOCAL then
  439. AllocGOTSlot(objreloc.symbol)
  440. else
  441. begin
  442. { Extract the addend, which is stored split between this relocation and
  443. the following (maybe not immediately) R_MIPS_LO16 one. }
  444. found:=false;
  445. for i:=idx+1 to objsec.ObjRelocations.Count-1 do
  446. begin
  447. lowreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  448. if (lowreloc.flags and rf_raw)=0 then
  449. InternalError(2013030101);
  450. if (lowreloc.ftype=R_MIPS_LO16) then
  451. begin;
  452. found:=true;
  453. break;
  454. end;
  455. end;
  456. if not found then
  457. InternalError(2013030102);
  458. objsec.Data.Seek(objreloc.DataOffset);
  459. objsec.Data.Read(hipart,sizeof(hipart));
  460. objsec.Data.Seek(lowreloc.DataOffset);
  461. objsec.Data.Read(lopart,sizeof(lopart));
  462. if (source_info.endian<>target_info.endian) then
  463. begin
  464. hipart:=swapendian(hipart);
  465. lopart:=swapendian(lopart);
  466. end;
  467. objreloc.orgsize:=(hipart shl 16)+SmallInt(lopart);
  468. local_got_relocs.add(objreloc);
  469. end;
  470. end;
  471. end;
  472. end;
  473. type
  474. PRelocData=^TRelocData;
  475. TRelocData=record
  476. next:PRelocData;
  477. objsec:TObjSection;
  478. objrel:TObjRelocation;
  479. addend:aint;
  480. end;
  481. procedure TElfExeOutputMIPS.DoRelocationFixup(objsec:TObjSection);
  482. var
  483. i,zero:longint;
  484. objreloc: TObjRelocation;
  485. AHL_S,
  486. tmp,
  487. address,
  488. relocval : aint;
  489. relocsec : TObjSection;
  490. data: TDynamicArray;
  491. reltyp: byte;
  492. curloc: aword;
  493. reloclist,hr: PRelocData;
  494. is_gp_disp: boolean;
  495. begin
  496. data:=objsec.data;
  497. reloclist:=nil;
  498. for i:=0 to objsec.ObjRelocations.Count-1 do
  499. begin
  500. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  501. case objreloc.typ of
  502. RELOC_NONE:
  503. continue;
  504. RELOC_ZERO:
  505. begin
  506. data.Seek(objreloc.dataoffset);
  507. zero:=0;
  508. data.Write(zero,4);
  509. continue;
  510. end;
  511. end;
  512. if (objreloc.flags and rf_raw)=0 then
  513. reltyp:=ElfTarget.encodereloc(objreloc)
  514. else
  515. reltyp:=objreloc.ftype;
  516. if ElfTarget.relocs_use_addend then
  517. address:=objreloc.orgsize
  518. else
  519. begin
  520. data.Seek(objreloc.dataoffset);
  521. data.Read(address,4);
  522. if source_info.endian<>target_info.endian then
  523. address:=swapendian(address);
  524. end;
  525. if assigned(objreloc.symbol) then
  526. begin
  527. relocsec:=objreloc.symbol.objsection;
  528. relocval:=objreloc.symbol.address;
  529. end
  530. else if assigned(objreloc.objsection) then
  531. begin
  532. relocsec:=objreloc.objsection;
  533. relocval:=objreloc.objsection.mempos
  534. end
  535. else
  536. internalerror(2012060702);
  537. { Only debug sections are allowed to have relocs pointing to unused sections }
  538. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  539. not (oso_debug in objsec.secoptions) then
  540. begin
  541. writeln(objsec.fullname,' references ',relocsec.fullname);
  542. internalerror(2012060703);
  543. end;
  544. curloc:=objsec.mempos+objreloc.dataoffset;
  545. if (relocsec=nil) or (relocsec.used) then
  546. case reltyp of
  547. R_MIPS_32:
  548. begin
  549. address:=address+relocval;
  550. if (objreloc.flags and rf_dynamic)<>0 then
  551. begin
  552. if (objreloc.symbol=nil) or
  553. (objreloc.symbol.exesymbol=nil) or
  554. (objreloc.symbol.exesymbol.dynindex=0) then
  555. WriteDynRelocEntry(curloc,R_MIPS_REL32,0,address)
  556. else
  557. dynreloclist.add(TObjRelocation.CreateRaw(curloc,objreloc.symbol,R_MIPS_REL32));
  558. end;
  559. end;
  560. R_MIPS_26:
  561. begin
  562. tmp:=(address and $03FFFFFF) shl 2;
  563. tmp:=((tmp or (curloc and $F0000000))+relocval) shr 2;
  564. address:=(address and $FC000000) or (tmp and $3FFFFFF);
  565. end;
  566. R_MIPS_HI16:
  567. begin
  568. { This relocation can be handled only after seeing a matching LO16 one,
  569. moreover BFD supports any number of HI16 to precede a single LO16.
  570. So just add it to a queue. }
  571. new(hr);
  572. hr^.next:=reloclist;
  573. hr^.objrel:=objreloc;
  574. hr^.objsec:=objsec;
  575. hr^.addend:=address; //TODO: maybe it can be saved in objrel.orgsize field
  576. reloclist:=hr;
  577. end;
  578. R_MIPS_LO16:
  579. begin
  580. { LO16 may be without pair, e.g. in following sequence:
  581. lui $v0, %hi(foo)
  582. lw $a0, %lo(foo)($v0)
  583. lw $a1, %lo(foo+4)($v0)
  584. }
  585. AHL_S:=SmallInt(address)+relocval;
  586. is_gp_disp:=false;
  587. while assigned(reloclist) do
  588. begin
  589. hr:=reloclist;
  590. reloclist:=hr^.next;
  591. // if relocval<>hr^.relocval then // must be the same symbol
  592. // InternalError();
  593. { _gp_disp and __gnu_local_gp magic }
  594. if assigned(hr^.objrel.symbol) and
  595. (hr^.objrel.symbol.bind<>AB_LOCAL) then
  596. begin
  597. is_gp_disp:=(hr^.objrel.symbol.exesymbol.objsymbol=gpdispsym);
  598. if (hr^.objrel.symbol.exesymbol.objsymbol=gnugpsym) then
  599. relocval:=gotsymbol.address;
  600. end;
  601. { in case of _gp_disp, non-zero addend is not possible? }
  602. { 4 must be added right here, so possible overflow in low half
  603. is propagated into high one (e.g if displacement is $37ffc,
  604. high part must be 4, not 3) }
  605. if is_gp_disp then
  606. relocval:=gotsymbol.address-curloc+4;
  607. AHL_S:=(hr^.addend shl 16)+SmallInt(address)+relocval;
  608. case hr^.objrel.ftype of
  609. R_MIPS_HI16:
  610. tmp:=(AHL_S-SmallInt(AHL_S)) shr 16;
  611. R_MIPS_GOT16:
  612. tmp:=-(gotsymbol.offset-(hr^.objrel.symbol.offset-sizeof(pint)));
  613. else
  614. InternalError(2013030404);
  615. end;
  616. tmp:=(hr^.addend and $FFFF0000) or (tmp and $FFFF);
  617. data.seek(hr^.objrel.dataoffset);
  618. if source_info.endian<>target_info.endian then
  619. tmp:=swapendian(tmp);
  620. data.Write(tmp,4);
  621. dispose(hr);
  622. end;
  623. address:=(address and $FFFF0000) or (AHL_S and $FFFF);
  624. end;
  625. R_MIPS_CALL16,
  626. R_MIPS_GOT16:
  627. begin
  628. { GOT16 relocations against local symbols are followed by LO16 }
  629. if (objreloc.symbol.bind=AB_LOCAL) then
  630. begin
  631. new(hr);
  632. hr^.next:=reloclist;
  633. hr^.objrel:=objreloc;
  634. hr^.objsec:=objsec;
  635. hr^.addend:=address; //TODO: maybe it can be saved in objrel.orgsize field
  636. reloclist:=hr;
  637. continue;
  638. end;
  639. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  640. // !! this is correct only while _gp symbol is defined relative to .got !!
  641. relocval:=-(gotsymbol.offset-(objreloc.symbol.exesymbol.gotoffset-sizeof(pint)));
  642. // TODO: check overflow
  643. address:=(address and $FFFF0000) or (relocval and $FFFF);
  644. end;
  645. R_MIPS_PC16:
  646. //TODO: check overflow
  647. address:=(address and $FFFF0000) or ((((SmallInt(address) shl 2)+relocval-curloc) shr 2) and $FFFF);
  648. R_MIPS_JALR: {optimization hint, ignore for now }
  649. ;
  650. else
  651. begin
  652. writeln(objsec.fullname,'+',objreloc.dataoffset,' ',objreloc.ftype);
  653. internalerror(200604014);
  654. end;
  655. end
  656. else { not relocsec.Used }
  657. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  658. data.Seek(objreloc.dataoffset);
  659. if source_info.endian<>target_info.endian then
  660. address:=swapendian(address);
  661. data.Write(address,4);
  662. end;
  663. end;
  664. {*****************************************************************************
  665. Initialize
  666. *****************************************************************************}
  667. const
  668. elf_target_mips: TElfTarget =
  669. (
  670. max_page_size: $10000;
  671. exe_image_base: $400000;
  672. machine_code: EM_MIPS;
  673. relocs_use_addend: false;
  674. dyn_reloc_codes: (
  675. 0,
  676. 0,
  677. 0,
  678. 0,
  679. 0
  680. );
  681. relocname: @elf_mips_relocName;
  682. encodereloc: @elf_mips_encodeReloc;
  683. loadreloc: @elf_mips_loadReloc;
  684. loadsection: @elf_mips_loadSection;
  685. );
  686. initialization
  687. ElfTarget:=elf_target_mips;
  688. ElfExeOutputClass:=TElfExeOutputMIPS;
  689. end.