cpuelf.pas 34 KB

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