cpuelf.pas 34 KB

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