cpuelf.pas 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990
  1. {
  2. Copyright (c) 2012 by Sergei Gorelkin
  3. Includes ELF-related code specific to ARM
  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,globals,cutils,cclasses,
  23. verbose, elfbase,
  24. systems,aasmbase,ogbase,ogelf,assemble;
  25. type
  26. TElfExeOutputARM=class(TElfExeOutput)
  27. private
  28. procedure MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  29. protected
  30. procedure WriteFirstPLTEntry;override;
  31. procedure WritePLTEntry(exesym:TExeSymbol);override;
  32. procedure WriteIndirectPLTEntry(exesym:TExeSymbol);override;
  33. procedure GOTRelocPass1(objsec:TObjSection;var idx:longint);override;
  34. procedure DoRelocationFixup(objsec:TObjSection);override;
  35. end;
  36. const
  37. { Relocation types }
  38. R_ARM_NONE = 0;
  39. R_ARM_PC24 = 1; // deprecated
  40. R_ARM_ABS32 = 2;
  41. R_ARM_REL32 = 3;
  42. R_ARM_LDR_PC_G0 = 4;
  43. R_ARM_ABS16 = 5;
  44. R_ARM_ABS12 = 6;
  45. R_ARM_THM_ABS5 = 7;
  46. R_ARM_ABS8 = 8;
  47. R_ARM_SBREL32 = 9;
  48. R_ARM_THM_CALL = 10;
  49. R_ARM_THM_PC8 = 11;
  50. R_ARM_BREL_ADJ = 12;
  51. R_ARM_TLS_DESC = 13;
  52. { 14,15,16 are obsolete }
  53. R_ARM_TLS_DTPMOD32 = 17;
  54. R_ARM_TLS_DTPOFF32 = 18;
  55. R_ARM_TLS_TPOFF32 = 19;
  56. R_ARM_COPY = 20;
  57. R_ARM_GLOB_DAT = 21;
  58. R_ARM_JUMP_SLOT = 22;
  59. R_ARM_RELATIVE = 23;
  60. R_ARM_GOTOFF32 = 24;
  61. R_ARM_BASE_PREL = 25;
  62. R_ARM_GOT_BREL = 26;
  63. R_ARM_PLT32 = 27; // deprecated
  64. R_ARM_CALL = 28;
  65. R_ARM_JUMP24 = 29;
  66. R_ARM_THM_JUMP24 = 30;
  67. R_ARM_BASE_ABS = 31;
  68. { 32,33,34 are obsolete }
  69. R_ARM_LDR_SBREL_11_0 = 35; // deprecated
  70. R_ARM_ALU_SBREL_19_12 = 36; // deprecated
  71. R_ARM_ALU_SBREL_27_20 = 37; // deprecated
  72. R_ARM_TARGET1 = 38;
  73. R_ARM_SBREL31 = 39; // deprecated
  74. R_ARM_V4BX = 40;
  75. R_ARM_TARGET2 = 41;
  76. R_ARM_PREL31 = 42;
  77. R_ARM_MOVW_ABS_NC = 43;
  78. R_ARM_MOVT_ABS = 44;
  79. R_ARM_MOVW_PREL_NC = 45;
  80. R_ARM_MOVT_PREL = 46;
  81. R_ARM_THM_MOVW_ABS_NC = 47;
  82. R_ARM_THM_MOVT_ABS = 48;
  83. R_ARM_THM_MOVW_PREL_NC = 49;
  84. R_ARM_THM_MOVT_PREL = 50;
  85. R_ARM_THM_JUMP19 = 51;
  86. R_ARM_THM_JUMP6 = 52;
  87. R_ARM_THM_ALU_PREL_11_0 = 53;
  88. R_ARM_THM_PC12 = 54;
  89. R_ARM_ABS32_NOI = 55;
  90. R_ARM_REL32_NOI = 56;
  91. R_ARM_ALU_PC_G0_NC = 57;
  92. R_ARM_ALU_PC_G0 = 58;
  93. R_ARM_ALU_PC_G1_NC = 59;
  94. R_ARM_ALU_PC_G1 = 60;
  95. R_ARM_ALU_PC_G2 = 61;
  96. R_ARM_LDR_PC_G1 = 62;
  97. R_ARM_LDR_PC_G2 = 63;
  98. R_ARM_LDRS_PC_G0 = 64;
  99. R_ARM_LDRS_PC_G1 = 65;
  100. R_ARM_LDRS_PC_G2 = 66;
  101. R_ARM_LDC_PC_G0 = 67;
  102. R_ARM_LDC_PC_G1 = 68;
  103. R_ARM_LDC_PC_G2 = 69;
  104. R_ARM_ALU_SB_G0_NC = 70;
  105. R_ARM_ALU_SB_G0 = 71;
  106. R_ARM_ALU_SB_G1_NC = 72;
  107. R_ARM_ALU_SB_G1 = 73;
  108. R_ARM_ALU_SB_G2 = 74;
  109. R_ARM_LDR_SB_G0 = 75;
  110. R_ARM_LDR_SB_G1 = 76;
  111. R_ARM_LDR_SB_G2 = 77;
  112. R_ARM_LDRS_SB_G0 = 78;
  113. R_ARM_LDRS_SB_G1 = 79;
  114. R_ARM_LDRS_SB_G2 = 80;
  115. R_ARM_LDC_SB_G0 = 81;
  116. R_ARM_LDC_SB_G1 = 82;
  117. R_ARM_LDC_SB_G2 = 83;
  118. R_ARM_MOVW_BREL_NC = 84;
  119. R_ARM_MOVT_BREL = 85;
  120. R_ARM_MOVW_BREL = 86;
  121. R_ARM_THM_MOVW_BREL_NC = 87;
  122. R_ARM_THM_MOVT_BREL = 88;
  123. R_ARM_THM_MOVW_BREL = 89;
  124. R_ARM_TLS_GOTDESC = 90;
  125. R_ARM_TLS_CALL = 91;
  126. R_ARM_TLS_DESCSEQ = 92;
  127. R_ARM_THM_TLS_CALL = 93;
  128. R_ARM_PLT32_ABS = 94;
  129. R_ARM_GOT_ABS = 95;
  130. R_ARM_GOT_PREL = 96;
  131. R_ARM_GOT_BREL12 = 97;
  132. R_ARM_GOTOFF12 = 98;
  133. R_ARM_GOTRELAX = 99;
  134. R_ARM_GNU_VTENTRY = 100; // deprecated - old C++ abi
  135. R_ARM_GNU_VTINHERIT = 101; // deprecated - old C++ abi
  136. R_ARM_THM_JUMP11 = 102;
  137. R_ARM_THM_JUMP8 = 103;
  138. R_ARM_TLS_GD32 = 104;
  139. R_ARM_TLS_LDM32 = 105;
  140. R_ARM_TLS_LDO32 = 106;
  141. R_ARM_TLS_IE32 = 107;
  142. R_ARM_TLS_LE32 = 108;
  143. R_ARM_TLS_LDO12 = 109;
  144. R_ARM_TLS_LE12 = 110;
  145. R_ARM_TLS_IE12GP = 111;
  146. { 112-127 are for private experiments }
  147. { 128 is obsolete }
  148. R_ARM_THM_TLS_DESCSEQ = 129;
  149. R_ARM_IRELATIVE = 160;
  150. { Section types }
  151. SHT_ARM_EXIDX = $70000001;
  152. SHT_ARM_PREEMPTMAP = $70000002;
  153. SHT_ARM_ATTRIBUTES = $70000003;
  154. SHT_ARM_DEBUGOVERLAY = $70000004;
  155. SHT_ARM_OVERLAYSECTION = $70000005;
  156. TCB_SIZE = 8;
  157. { ELF header e_flags }
  158. EF_ARM_BE8 = $00800000;
  159. EF_ARM_EABIMASK = $FF000000;
  160. EF_ARM_EABI_UNKNOWN = $00000000;
  161. EF_ARM_EABI_VER1 = $01000000;
  162. EF_ARM_EABI_VER2 = $02000000;
  163. EF_ARM_EABI_VER3 = $03000000;
  164. EF_ARM_EABI_VER4 = $04000000;
  165. EF_ARM_EABI_VER5 = $05000000;
  166. { Using short identifiers to save typing. This ARM thing has more relocations
  167. than it has instructions... }
  168. const
  169. g0=1;
  170. g1=2;
  171. g2=3;
  172. gpmask=3;
  173. pc=4;
  174. nc=8;
  175. thm=16;
  176. type
  177. TArmRelocProp=record
  178. name: PChar;
  179. flags: byte; // bits 0,1: group, bit 2: PC-relative, bit 3: unchecked,
  180. // bit 4: THUMB
  181. end;
  182. const
  183. relocprops: array[0..111] of TArmRelocProp = (
  184. (name: 'R_ARM_NONE'; flags: 0), //
  185. (name: 'R_ARM_PC24'; flags: pc), //
  186. (name: 'R_ARM_ABS32'; flags: 0), //
  187. (name: 'R_ARM_REL32'; flags: pc), //
  188. (name: 'R_ARM_LDR_PC_G0'; flags: g0+pc), //
  189. (name: 'R_ARM_ABS16'; flags: 0),
  190. (name: 'R_ARM_ABS12'; flags: 0),
  191. (name: 'R_ARM_THM_ABS5'; flags: thm),
  192. (name: 'R_ARM_ABS8'; flags: 0),
  193. (name: 'R_ARM_SBREL32'; flags: 0),
  194. (name: 'R_ARM_THM_CALL'; flags: thm),
  195. (name: 'R_ARM_THM_PC8'; flags: pc+thm),
  196. (name: 'R_ARM_BREL_ADJ'; flags: 0),
  197. (name: 'R_ARM_TLS_DESC'; flags: 0),
  198. (name: 'obsolete(14)'; flags: 0),
  199. (name: 'obsolete(15)'; flags: 0),
  200. (name: 'obsolete(16)'; flags: 0),
  201. (name: 'R_ARM_TLS_DTPMOD32'; flags: 0),
  202. (name: 'R_ARM_TLS_DTPOFF32'; flags: 0),
  203. (name: 'R_ARM_TLS_TPOFF32'; flags: 0),
  204. (name: 'R_ARM_COPY'; flags: 0),
  205. (name: 'R_ARM_GLOB_DAT'; flags: 0),
  206. (name: 'R_ARM_JUMP_SLOT'; flags: 0),
  207. (name: 'R_ARM_RELATIVE'; flags: 0),
  208. (name: 'R_ARM_GOTOFF32'; flags: 0),
  209. (name: 'R_ARM_BASE_PREL'; flags: pc), //
  210. (name: 'R_ARM_GOT_BREL'; flags: 0), //
  211. (name: 'R_ARM_PLT32'; flags: pc), //
  212. (name: 'R_ARM_CALL'; flags: pc), //
  213. (name: 'R_ARM_JUMP24'; flags: pc), //
  214. (name: 'R_ARM_THM_JUMP24'; flags: thm),
  215. (name: 'R_ARM_BASE_ABS'; flags: 0),
  216. (name: 'obsolete(32)'; flags: 0),
  217. (name: 'obsolete(33)'; flags: 0),
  218. (name: 'obsolete(34)'; flags: 0),
  219. (name: 'R_ARM_LDR_SBREL_11_0'; flags: g0),
  220. (name: 'R_ARM_ALU_SBREL_19_12'; flags: g1),
  221. (name: 'R_ARM_ALU_SBREL_27_20'; flags: g2),
  222. (name: 'R_ARM_TARGET1'; flags: 0),
  223. (name: 'R_ARM_SBREL31'; flags: 0),
  224. (name: 'R_ARM_V4BX'; flags: 0),
  225. (name: 'R_ARM_TARGET2'; flags: 0),
  226. (name: 'R_ARM_PREL31'; flags: 0),
  227. (name: 'R_ARM_MOVW_ABS_NC'; flags: nc),
  228. (name: 'R_ARM_MOVT_ABS'; flags: 0),
  229. (name: 'R_ARM_MOVW_PREL_NC'; flags: nc),
  230. (name: 'R_ARM_MOVT_PREL'; flags: 0),
  231. (name: 'R_ARM_THM_MOVW_ABS_NC'; flags: nc+thm),
  232. (name: 'R_ARM_THM_MOVT_ABS'; flags: thm),
  233. (name: 'R_ARM_THM_MOVW_PREL_NC'; flags: nc+thm),
  234. (name: 'R_ARM_THM_MOVT_PREL'; flags: thm),
  235. (name: 'R_ARM_THM_JUMP19'; flags: thm),
  236. (name: 'R_ARM_THM_JUMP6'; flags: thm),
  237. (name: 'R_ARM_THM_ALU_PREL_11_0'; flags: thm+pc),
  238. (name: 'R_ARM_THM_PC12'; flags: thm+pc),
  239. (name: 'R_ARM_ABS32_NOI'; flags: 0),
  240. (name: 'R_ARM_REL32_NOI'; flags: pc),
  241. (name: 'R_ARM_ALU_PC_G0_NC'; flags: pc+g0+nc), //
  242. (name: 'R_ARM_ALU_PC_G0'; flags: pc+g0), //
  243. (name: 'R_ARM_ALU_PC_G1_NC'; flags: pc+g1+nc), //
  244. (name: 'R_ARM_ALU_PC_G1'; flags: pc+g1), //
  245. (name: 'R_ARM_ALU_PC_G2'; flags: pc+g2), //
  246. (name: 'R_ARM_LDR_PC_G1'; flags: pc+g1), //
  247. (name: 'R_ARM_LDR_PC_G2'; flags: pc+g2), //
  248. (name: 'R_ARM_LDRS_PC_G0'; flags: pc+g0), //
  249. (name: 'R_ARM_LDRS_PC_G1'; flags: pc+g1), //
  250. (name: 'R_ARM_LDRS_PC_G2'; flags: pc+g2), //
  251. (name: 'R_ARM_LDC_PC_G0'; flags: pc+g0), //
  252. (name: 'R_ARM_LDC_PC_G1'; flags: pc+g1), //
  253. (name: 'R_ARM_LDC_PC_G2'; flags: pc+g2), //
  254. (name: 'R_ARM_ALU_SB_G0_NC'; flags: g0+nc), //
  255. (name: 'R_ARM_ALU_SB_G0'; flags: g0), //
  256. (name: 'R_ARM_ALU_SB_G1_NC'; flags: g1+nc), //
  257. (name: 'R_ARM_ALU_SB_G1'; flags: g1), //
  258. (name: 'R_ARM_ALU_SB_G2'; flags: g2), //
  259. (name: 'R_ARM_LDR_SB_G0'; flags: g0), //
  260. (name: 'R_ARM_LDR_SB_G1'; flags: g1), //
  261. (name: 'R_ARM_LDR_SB_G2'; flags: g2), //
  262. (name: 'R_ARM_LDRS_SB_G0'; flags: g0), //
  263. (name: 'R_ARM_LDRS_SB_G1'; flags: g1), //
  264. (name: 'R_ARM_LDRS_SB_G2'; flags: g2), //
  265. (name: 'R_ARM_LDC_SB_G0'; flags: g0), //
  266. (name: 'R_ARM_LDC_SB_G1'; flags: g1), //
  267. (name: 'R_ARM_LDC_SB_G2'; flags: g2), //
  268. (name: 'R_ARM_MOVW_BREL_NC'; flags: nc),
  269. (name: 'R_ARM_MOVT_BREL'; flags: 0),
  270. (name: 'R_ARM_MOVW_BREL'; flags: 0),
  271. (name: 'R_ARM_THM_MOVW_BREL_NC'; flags: nc+thm),
  272. (name: 'R_ARM_THM_MOVT_BREL'; flags: thm),
  273. (name: 'R_ARM_THM_MOVW_BREL'; flags: thm),
  274. (name: 'R_ARM_TLS_GOTDESC'; flags: 0),
  275. (name: 'R_ARM_TLS_CALL'; flags: 0),
  276. (name: 'R_ARM_TLS_DESCSEQ'; flags: 0),
  277. (name: 'R_ARM_THM_TLS_CALL'; flags: 0),
  278. (name: 'R_ARM_PLT32_ABS'; flags: 0),
  279. (name: 'R_ARM_GOT_ABS'; flags: 0),
  280. (name: 'R_ARM_GOT_PREL'; flags: pc), //
  281. (name: 'R_ARM_GOT_BREL12'; flags: 0),
  282. (name: 'R_ARM_GOTOFF12'; flags: 0),
  283. (name: 'R_ARM_GOTRELAX'; flags: 0),
  284. (name: 'R_ARM_GNU_VTENTRY'; flags: 0),
  285. (name: 'R_ARM_GNU_VTINHERIT'; flags: 0),
  286. (name: 'R_ARM_THM_JUMP11'; flags: thm),
  287. (name: 'R_ARM_THM_JUMP8'; flags: thm),
  288. (name: 'R_ARM_TLS_GD32'; flags: 0),
  289. (name: 'R_ARM_TLS_LDM32'; flags: 0),
  290. (name: 'R_ARM_TLS_LDO32'; flags: 0),
  291. (name: 'R_ARM_TLS_IE32'; flags: 0),
  292. (name: 'R_ARM_TLS_LE32'; flags: 0),
  293. (name: 'R_ARM_TLS_LDO12'; flags: 0),
  294. (name: 'R_ARM_TLS_LE12'; flags: 0),
  295. (name: 'R_ARM_TLS_IE12GP'; flags: 0)
  296. );
  297. {****************************************************************************
  298. ELF Target methods
  299. ****************************************************************************}
  300. function elf_arm_encodereloc(objrel:TObjRelocation):byte;
  301. begin
  302. case objrel.typ of
  303. RELOC_NONE:
  304. result:=R_ARM_NONE;
  305. RELOC_ABSOLUTE:
  306. result:=R_ARM_ABS32;
  307. RELOC_RELATIVE:
  308. result:=R_ARM_REL32;
  309. RELOC_RELATIVE_24:
  310. result:=R_ARM_JUMP24;
  311. RELOC_RELATIVE_CALL:
  312. result:=R_ARM_CALL;
  313. RELOC_RELATIVE_24_THUMB:
  314. result:=R_ARM_CALL;
  315. RELOC_RELATIVE_CALL_THUMB:
  316. result:=R_ARM_THM_CALL;
  317. RELOC_GOT32:
  318. result:=R_ARM_GOT_BREL;
  319. RELOC_TPOFF:
  320. if current_settings.tlsmodel=tlsm_initial_exec then
  321. result:=R_ARM_TLS_IE32
  322. else if current_settings.tlsmodel=tlsm_local_exec then
  323. result:=R_ARM_TLS_LE32
  324. else
  325. Internalerror(2019092901);
  326. RELOC_TLSGD:
  327. result:=R_ARM_TLS_GD32;
  328. RELOC_TLSDESC:
  329. result:=R_ARM_TLS_GOTDESC;
  330. RELOC_TLS_CALL:
  331. result:=R_ARM_TLS_CALL;
  332. RELOC_ARM_CALL:
  333. result:=R_ARM_CALL;
  334. RELOC_DTPOFF:
  335. result:=R_ARM_TLS_LDO32;
  336. else
  337. InternalError(2012110602);
  338. end;
  339. end;
  340. function elf_arm_relocname(reltyp:byte):string;
  341. begin
  342. if reltyp<=high(relocprops) then
  343. result:=relocprops[reltyp].name
  344. else
  345. case reltyp of
  346. 112..127:
  347. result:='R_ARM_PRIVATE_'+tostr(reltyp-112);
  348. R_ARM_THM_TLS_DESCSEQ:
  349. result:='R_ARM_THM_TLS_DESCSEQ';
  350. R_ARM_IRELATIVE:
  351. result:='R_ARM_IRELATIVE';
  352. else
  353. result:='unknown ('+tostr(reltyp)+')';
  354. end;
  355. end;
  356. procedure elf_arm_loadreloc(objrel:TObjRelocation);
  357. begin
  358. if (objrel.ftype=R_ARM_V4BX) then
  359. objrel.flags:=objrel.flags or rf_nosymbol;
  360. end;
  361. function elf_arm_loadsection(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean;
  362. var
  363. secname:string;
  364. begin
  365. case shdr.sh_type of
  366. SHT_ARM_EXIDX,
  367. SHT_ARM_PREEMPTMAP,
  368. SHT_ARM_ATTRIBUTES:
  369. begin
  370. objinput.CreateSection(shdr,shindex,objdata,secname);
  371. result:=true;
  372. end;
  373. else
  374. writeln(hexstr(shdr.sh_type,8));
  375. result:=false;
  376. end;
  377. end;
  378. {****************************************************************************
  379. TELFExeOutputARM
  380. ****************************************************************************}
  381. function group_reloc_mask(value:longword;n:longint;out final_residual:longword):longword;
  382. var
  383. i:longint;
  384. g_n:longword;
  385. shift:longint;
  386. begin
  387. result:=0;
  388. for i:=0 to n do
  389. begin
  390. if (value=0) then
  391. shift:=0
  392. else
  393. { MSB in the residual, aligned to a 2-bit boundary }
  394. shift:=max(0,(bsrdword(value) and (not 1))-6);
  395. { Calculate plain g_n and encode it into constant+rotation form }
  396. g_n:=value and ($ff shl shift);
  397. result:=(g_n shr shift);
  398. if (g_n>$FF) then
  399. result:=result or ((32-shift) div 2) shl 8;
  400. { Mask away the processed part of residual }
  401. value:=value and (not g_n);
  402. end;
  403. final_residual:=value;
  404. end;
  405. procedure TElfExeOutputARM.MaybeWriteGOTEntry(reltyp:byte;relocval:aint;objsym:TObjSymbol);
  406. var
  407. gotoff,tmp:aword;
  408. begin
  409. gotoff:=objsym.exesymbol.gotoffset;
  410. if gotoff=0 then
  411. InternalError(2012060902);
  412. { the GOT slot itself, and a dynamic relocation for it }
  413. { TODO: only data symbols must get here }
  414. if gotoff=gotobjsec.Data.size+sizeof(pint) then
  415. begin
  416. gotobjsec.write(relocval,sizeof(pint));
  417. tmp:=gotobjsec.mempos+gotoff-sizeof(pint);
  418. if (objsym.exesymbol.dynindex>0) then
  419. begin
  420. WriteDynRelocEntry(tmp,R_ARM_GLOB_DAT,objsym.exesymbol.dynindex,0)
  421. end
  422. else if IsSharedLibrary then
  423. WriteDynRelocEntry(tmp,R_ARM_RELATIVE,0,relocval);
  424. end;
  425. end;
  426. procedure TElfExeOutputARM.WriteFirstPLTEntry;
  427. begin
  428. pltobjsec.WriteBytes(
  429. #$04#$E0#$2D#$E5+ // str lr, [sp, #-4]!
  430. #$04#$E0#$9F#$E5+ // ldr lr, [pc, #4]
  431. #$0E#$E0#$8F#$E0+ // add lr, pc, lr
  432. #$08#$F0#$BE#$E5); // ldr pc, [lr, #8]!
  433. // .long _GLOBAL_OFFSET_TABLE-.
  434. pltobjsec.writeReloc_internal(gotpltobjsec,0,4,RELOC_RELATIVE);
  435. end;
  436. procedure TElfExeOutputARM.WritePLTEntry(exesym: TExeSymbol);
  437. var
  438. tmp: longword;
  439. sym:TObjSymbol;
  440. begin
  441. { TODO: it may be beneficial to postpone processing until after mempos pass,
  442. and calculate instructions directly, instead of messing with complex relocations. }
  443. { Group relocation to "section+offset" with REL-style is impossible, because the
  444. offset has be encoded into instructions, and it is only possible for offsets
  445. representable as shifter constants. Therefore we need to define a symbol
  446. (and risk a name conflict, to some degree) }
  447. internalobjdata.setsection(gotpltobjsec);
  448. sym:=internalobjdata.SymbolDefine(exesym.name+'_ptr',AB_LOCAL,AT_DATA);
  449. pltobjsec.WriteBytes(
  450. #$08#$C0#$4F#$E2+ // add ip,pc,#:pc_g0_nc:sym-8
  451. #$04#$C0#$4C#$E2+ // add ip,ip,#:pc_g1_nc:sym-4
  452. #$00#$F0#$BC#$E5); // ldr pc,[ip,#:pc_g2:sym]!
  453. pltobjsec.addrawReloc(pltobjsec.size-12,sym,R_ARM_ALU_PC_G0_NC);
  454. pltobjsec.addrawReloc(pltobjsec.size-8,sym,R_ARM_ALU_PC_G1_NC);
  455. pltobjsec.addrawReloc(pltobjsec.size-4,sym,R_ARM_LDR_PC_G2);
  456. { .got.plt slot initially points to the first PLT entry }
  457. gotpltobjsec.writeReloc_internal(pltobjsec,0,sizeof(pint),RELOC_ABSOLUTE);
  458. { write a .rel.plt entry (Elf32_rel record) }
  459. pltrelocsec.writeReloc_internal(gotpltobjsec,gotpltobjsec.size-sizeof(pint),sizeof(pint),RELOC_ABSOLUTE);
  460. tmp:=(exesym.dynindex shl 8) or R_ARM_JUMP_SLOT;
  461. pltrelocsec.write(tmp,sizeof(tmp));
  462. if ElfTarget.relocs_use_addend then
  463. pltrelocsec.writezeros(sizeof(pint));
  464. end;
  465. procedure TElfExeOutputARM.WriteIndirectPLTEntry(exesym: TExeSymbol);
  466. begin
  467. inherited WriteIndirectPLTEntry(exesym);
  468. end;
  469. procedure TElfExeOutputARM.GOTRelocPass1(objsec:TObjSection;var idx:longint);
  470. var
  471. objreloc:TObjRelocation;
  472. exesym:TExeSymbol;
  473. objsym:TObjSymbol;
  474. reltyp:byte;
  475. begin
  476. objreloc:=TObjRelocation(objsec.ObjRelocations[idx]);
  477. if (ObjReloc.flags and rf_raw)=0 then
  478. reltyp:=ElfTarget.encodereloc(ObjReloc)
  479. else
  480. reltyp:=ObjReloc.ftype;
  481. case reltyp of
  482. // Any call or jump can go through PLT, no x86-like segregation here.
  483. R_ARM_PC24,
  484. R_ARM_CALL,
  485. R_ARM_JUMP24,
  486. R_ARM_PREL31,
  487. R_ARM_THM_CALL,
  488. R_ARM_THM_JUMP24,
  489. R_ARM_THM_JUMP19,
  490. R_ARM_PLT32:
  491. begin
  492. if (objreloc.symbol=nil) or (objreloc.symbol.exesymbol=nil) then
  493. exit;
  494. exesym:=objreloc.symbol.exesymbol;
  495. exesym.objsymbol.refs:=exesym.objsymbol.refs or symref_plt;
  496. end;
  497. R_ARM_ABS32:
  498. if Assigned(ObjReloc.symbol.exesymbol) then
  499. begin
  500. objsym:=ObjReloc.symbol.exesymbol.ObjSymbol;
  501. if (oso_executable in objsec.SecOptions) or
  502. not (oso_write in objsec.SecOptions) then
  503. objsym.refs:=objsym.refs or symref_from_text;
  504. end;
  505. end;
  506. case reltyp of
  507. R_ARM_ABS32:
  508. begin
  509. if not IsSharedLibrary then
  510. exit;
  511. if (oso_executable in objsec.SecOptions) or
  512. not (oso_write in objsec.SecOptions) then
  513. hastextrelocs:=True;
  514. dynrelocsec.alloc(dynrelocsec.shentsize);
  515. objreloc.flags:=objreloc.flags or rf_dynamic;
  516. end;
  517. //R_ARM_GOT_ABS,
  518. //R_ARM_GOT_PREL,
  519. //R_ARM_GOT_BREL12,
  520. R_ARM_GOT_BREL:
  521. begin
  522. AllocGOTSlot(objreloc.symbol);
  523. end;
  524. R_ARM_TLS_IE32:
  525. AllocGOTSlot(objreloc.symbol);
  526. end;
  527. end;
  528. procedure TElfExeOutputARM.DoRelocationFixup(objsec:TObjSection);
  529. var
  530. i,zero:longint;
  531. objreloc: TObjRelocation;
  532. tmp,
  533. address,
  534. relocval : aint;
  535. relocsec : TObjSection;
  536. data: TDynamicArray;
  537. reltyp: byte;
  538. group:longint;
  539. rotation:longint;
  540. residual,g_n:longword;
  541. curloc: aword;
  542. bit_S,bit_I1,bit_I2: aint;
  543. begin
  544. data:=objsec.data;
  545. for i:=0 to objsec.ObjRelocations.Count-1 do
  546. begin
  547. objreloc:=TObjRelocation(objsec.ObjRelocations[i]);
  548. case objreloc.typ of
  549. RELOC_NONE:
  550. continue;
  551. RELOC_ZERO:
  552. begin
  553. data.Seek(objreloc.dataoffset);
  554. zero:=0;
  555. data.Write(zero,4);
  556. continue;
  557. end;
  558. else
  559. ;
  560. end;
  561. if (objreloc.flags and rf_raw)=0 then
  562. reltyp:=ElfTarget.encodereloc(objreloc)
  563. else
  564. reltyp:=objreloc.ftype;
  565. { TODO: TARGET1 and TARGET2 are intended to be configured via commandline }
  566. if (reltyp=R_ARM_TARGET1) then
  567. reltyp:=R_ARM_ABS32; { may be ABS32 or REL32 }
  568. if (reltyp=R_ARM_TARGET2) then
  569. reltyp:=R_ARM_ABS32; { may be ABS32,REL32 or GOT_PREL }
  570. if ElfTarget.relocs_use_addend then
  571. address:=objreloc.orgsize
  572. else
  573. begin
  574. data.Seek(objreloc.dataoffset);
  575. data.Read(address,4);
  576. end;
  577. if assigned(objreloc.symbol) then
  578. begin
  579. relocsec:=objreloc.symbol.objsection;
  580. relocval:=objreloc.symbol.address;
  581. end
  582. else if assigned(objreloc.objsection) then
  583. begin
  584. relocsec:=objreloc.objsection;
  585. relocval:=objreloc.objsection.mempos
  586. end
  587. else if (reltyp=R_ARM_V4BX) then
  588. continue // ignore for now
  589. else
  590. internalerror(2012060702);
  591. { Only debug sections are allowed to have relocs pointing to unused sections }
  592. if assigned(relocsec) and not (relocsec.used and assigned(relocsec.exesection)) and
  593. not (oso_debug in objsec.secoptions) then
  594. begin
  595. writeln(objsec.fullname,' references ',relocsec.fullname);
  596. internalerror(2012060703);
  597. end;
  598. curloc:=objsec.mempos+objreloc.dataoffset;
  599. if (relocsec=nil) or (relocsec.used) then
  600. case reltyp of
  601. R_ARM_ABS32:
  602. begin
  603. if (objreloc.flags and rf_dynamic)<>0 then
  604. begin
  605. if (objreloc.symbol=nil) or
  606. (objreloc.symbol.exesymbol=nil) or
  607. (objreloc.symbol.exesymbol.dynindex=0) then
  608. begin
  609. address:=address+relocval;
  610. WriteDynRelocEntry(objreloc.dataoffset+objsec.mempos,R_ARM_RELATIVE,0,address);
  611. end
  612. else
  613. { Don't modify address in this case, as it serves as addend for RTLD }
  614. WriteDynRelocEntry(objreloc.dataoffset+objsec.mempos,R_ARM_ABS32,objreloc.symbol.exesymbol.dynindex,0);
  615. end
  616. else
  617. address:=address+relocval;
  618. end;
  619. R_ARM_REL32:
  620. begin
  621. address:=address+relocval-curloc;
  622. end;
  623. R_ARM_PC24,
  624. R_ARM_PLT32,
  625. R_ARM_JUMP24,
  626. R_ARM_CALL:
  627. begin
  628. { R_ARM_PC24 is deprecated in favour of R_ARM_JUMP24 and R_ARM_CALL,
  629. which allow to distinguish opcodes without examining them.
  630. Difference is:
  631. 1) when target is Thumb, BL can be changed to BLX, while B has
  632. to go via thunking code.
  633. 2) when target is unresolved weak symbol, CALL must be changed to NOP,
  634. while JUMP24 behavior is unspecified. }
  635. tmp:=sarlongint((address and $00FFFFFF) shl 8,6);
  636. tmp:=tmp+relocval;
  637. if odd(tmp) then { dest is Thumb? }
  638. begin
  639. if (reltyp=R_ARM_CALL) then
  640. { change BL to BLX, dest bit 1 goes to instruction bit 24 }
  641. address:=(address and $FE000000) or (((tmp-curloc) and 2) shl 23) or $F0000000
  642. else
  643. InternalError(2014092001);
  644. end
  645. else if (address and $FF000000)=$FA000000 then
  646. begin
  647. { Change BLX to BL }
  648. address:=(address and $EA000000) or $01000000;
  649. end;
  650. tmp:=tmp-curloc;
  651. // TODO: check overflow
  652. address:=(address and $FF000000) or ((tmp and $3FFFFFE) shr 2);
  653. end;
  654. R_ARM_BASE_PREL: { GOTPC }
  655. address:=address+gotsymbol.address-curloc;
  656. R_ARM_GOT_BREL: { GOT32 }
  657. begin
  658. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  659. address:=address+gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint)-gotsymbol.address;
  660. end;
  661. R_ARM_GOTOFF32:
  662. address:=address+relocval-gotsymbol.address;
  663. R_ARM_ALU_PC_G0_NC,
  664. R_ARM_ALU_PC_G1_NC,
  665. R_ARM_ALU_PC_G0,
  666. R_ARM_ALU_PC_G1,
  667. R_ARM_ALU_PC_G2,
  668. R_ARM_ALU_SB_G0_NC,
  669. R_ARM_ALU_SB_G1_NC,
  670. R_ARM_ALU_SB_G0,
  671. R_ARM_ALU_SB_G1,
  672. R_ARM_ALU_SB_G2:
  673. begin
  674. group:=(relocprops[reltyp].flags and gpmask)-1;
  675. if group<0 then
  676. InternalError(2012112601);
  677. if (not ElfTarget.relocs_use_addend) then
  678. begin
  679. { initial addend must be determined by parsing the instruction }
  680. tmp:=address and $FF;
  681. rotation:=(address and $F00) shr 7; { is in multpile of 2 bits }
  682. if rotation<>0 then
  683. tmp:=RorDword(tmp,rotation);
  684. case (address and $1E00000) of
  685. 1 shl 23: ; { ADD instruction }
  686. 1 shl 22: tmp:=-tmp; { SUB instruction }
  687. else
  688. Comment(v_error,'Group ALU relocations are permitted only for ADD or SUB instructions');
  689. continue;
  690. end;
  691. end
  692. else { TODO: must read the instruction anyway!! }
  693. tmp:=address;
  694. if (relocprops[reltyp].flags and pc)<>0 then
  695. tmp:=tmp+relocval-curloc
  696. else
  697. tmp:=tmp+relocval{-SB}; { assuming zero segment base }
  698. g_n:=group_reloc_mask(abs(tmp),group,residual);
  699. {TODO: check for overflow}
  700. address:=address and $FF1FF000 or g_n;
  701. { set opcode depending on the sign of resulting value }
  702. if tmp<0 then
  703. address:=address or (1 shl 22)
  704. else
  705. address:=address or (1 shl 23);
  706. end;
  707. R_ARM_LDR_PC_G0,
  708. R_ARM_LDR_PC_G1,
  709. R_ARM_LDR_PC_G2,
  710. R_ARM_LDR_SB_G0,
  711. R_ARM_LDR_SB_G1,
  712. R_ARM_LDR_SB_G2:
  713. begin
  714. group:=(relocprops[reltyp].flags and gpmask)-1;
  715. if group<0 then
  716. InternalError(2012112602);
  717. if (not ElfTarget.relocs_use_addend) then
  718. begin
  719. tmp:=(address and $FFF);
  720. if (address and (1 shl 23))=0 then
  721. tmp:=-tmp;
  722. end
  723. else { TODO: must read the instruction anyway }
  724. tmp:=address;
  725. if (relocprops[reltyp].flags and pc)<>0 then
  726. tmp:=tmp+relocval-curloc
  727. else
  728. tmp:=tmp+relocval{-SB}; { assuming zero segment base }
  729. group_reloc_mask(abs(tmp),group-1,residual);
  730. if residual>$FFF then
  731. InternalError(2012112603); { TODO: meaningful overflow error message }
  732. address:=address and $FF7FF000 or residual;
  733. if tmp>=0 then
  734. address:=address or (1 shl 23);
  735. end;
  736. R_ARM_LDRS_PC_G0,
  737. R_ARM_LDRS_PC_G1,
  738. R_ARM_LDRS_PC_G2,
  739. R_ARM_LDRS_SB_G0,
  740. R_ARM_LDRS_SB_G1,
  741. R_ARM_LDRS_SB_G2:
  742. begin
  743. group:=(relocprops[reltyp].flags and gpmask)-1;
  744. if group<0 then
  745. InternalError(2012112606);
  746. if (not ElfTarget.relocs_use_addend) then
  747. begin
  748. tmp:=((address and $F00) shr 4) or (address and $F);
  749. if (address and (1 shl 23))=0 then
  750. tmp:=-tmp;
  751. end
  752. else { TODO: must read the instruction anyway }
  753. tmp:=address;
  754. if (relocprops[reltyp].flags and pc)<>0 then
  755. tmp:=tmp+relocval-curloc
  756. else
  757. tmp:=tmp+relocval{-SB}; { assuming zero segment base }
  758. group_reloc_mask(abs(tmp),group-1,residual);
  759. if (residual>$FF) then
  760. InternalError(2012112607); { TODO: meaningful overflow error message }
  761. address:=address and $FF7FF0F0 or ((residual and $F0) shl 4) or (residual and $F);
  762. if tmp>=0 then
  763. address:=address or (1 shl 23);
  764. end;
  765. R_ARM_LDC_PC_G0,
  766. R_ARM_LDC_PC_G1,
  767. R_ARM_LDC_PC_G2,
  768. R_ARM_LDC_SB_G0,
  769. R_ARM_LDC_SB_G1,
  770. R_ARM_LDC_SB_G2:
  771. begin
  772. group:=(relocprops[reltyp].flags and gpmask)-1;
  773. if group<0 then
  774. InternalError(2012112604);
  775. if (not ElfTarget.relocs_use_addend) then
  776. begin
  777. tmp:=(address and $FF) shl 2;
  778. if (address and (1 shl 23))=0 then
  779. tmp:=-tmp;
  780. end
  781. else { TODO: must read the instruction anyway }
  782. tmp:=address;
  783. if (relocprops[reltyp].flags and pc)<>0 then
  784. tmp:=tmp+relocval-curloc
  785. else
  786. tmp:=tmp+relocval{-SB}; { assuming zero segment base }
  787. group_reloc_mask(abs(tmp),group-1,residual);
  788. { residual must be divisible by 4 and fit into 8 bits after having been divided }
  789. if ((residual and 3)<>0) or (residual>$3FF) then
  790. InternalError(2012112605); { TODO: meaningful overflow error message }
  791. address:=address and $FF7FFF00 or (residual shr 2);
  792. if tmp>=0 then
  793. address:=address or (1 shl 23);
  794. end;
  795. R_ARM_THM_CALL:
  796. begin
  797. if (not ElfTarget.relocs_use_addend) then
  798. begin
  799. address:=((address and $ffff) shl 16) or word(address shr 16);
  800. bit_S:=(address shr 26) and 1;
  801. bit_I1:=(bit_S xor ((address shr 13) and 1)) xor 1;
  802. bit_I2:=(bit_S xor ((address shr 11) and 1)) xor 1;
  803. tmp:=((-bit_S) shl 24) or (bit_I1 shl 23) or (bit_I2 shl 22) or (((address shr 16) and $3ff) shl 12) or ((address and $7ff) shl 1);
  804. end
  805. else { TODO: must read the instruction anyway }
  806. tmp:=address;
  807. tmp:=tmp+relocval; { dest address }
  808. if odd(tmp) then { if it's Thumb code, change possible BLX to BL }
  809. address:=address or $1800;
  810. tmp:=tmp-curloc; { now take PC-relative }
  811. { TODO: overflow check, different limit for Thumb and Thumb-2 }
  812. { now encode this mess back }
  813. if (address and $5000)=$4000 then
  814. tmp:=(tmp+2) and (not 3);
  815. bit_S:=(tmp shr 31) and 1;
  816. address:=(address and $F800D000) or
  817. (bit_S shl 26) or
  818. (((tmp shr 12) and $3ff) shl 16) or
  819. ((tmp shr 1) and $7FF) or
  820. ((((tmp shr 23) and 1) xor 1 xor bit_S) shl 13) or
  821. ((((tmp shr 22) and 1) xor 1 xor bit_S) shl 11);
  822. address:=((address and $ffff) shl 16) or word(address shr 16);
  823. end;
  824. R_ARM_TLS_IE32:
  825. begin
  826. relocval:=relocval-tlsseg.mempos+align_aword(TCB_SIZE,tlsseg.align);
  827. MaybeWriteGOTEntry(reltyp,relocval,objreloc.symbol);
  828. { resolves to PC-relative offset to GOT slot }
  829. relocval:=gotobjsec.mempos+objreloc.symbol.exesymbol.gotoffset-sizeof(pint);
  830. address:=address+relocval-curloc;
  831. end;
  832. R_ARM_TLS_LE32:
  833. if IsSharedLibrary then
  834. { TODO: error message saying "recompile with -Cg" isn't correct. Or is it? }
  835. ReportNonDSOReloc(reltyp,objsec,objreloc)
  836. else
  837. address:=relocval-tlsseg.mempos+align_aword(TCB_SIZE,tlsseg.align);
  838. else
  839. begin
  840. writeln(objreloc.ftype);
  841. internalerror(200604014);
  842. end;
  843. end
  844. else { not relocsec.Used }
  845. address:=0; { Relocation in debug section points to unused section, which is eliminated by linker }
  846. data.Seek(objreloc.dataoffset);
  847. data.Write(address,4);
  848. end;
  849. end;
  850. function elf_arm_encodeflags: longword;
  851. begin
  852. result:=EF_ARM_EABI_VER5;
  853. end;
  854. {*****************************************************************************
  855. Initialize
  856. *****************************************************************************}
  857. const
  858. elf_target_arm: TElfTarget =
  859. (
  860. max_page_size: $8000;
  861. exe_image_base: $8000;
  862. machine_code: EM_ARM;
  863. relocs_use_addend: false;
  864. dyn_reloc_codes: (
  865. R_ARM_RELATIVE,
  866. R_ARM_GLOB_DAT,
  867. R_ARM_JUMP_SLOT,
  868. R_ARM_COPY,
  869. R_ARM_IRELATIVE
  870. );
  871. relocname: @elf_arm_relocName;
  872. encodereloc: @elf_arm_encodeReloc;
  873. loadreloc: @elf_arm_loadReloc;
  874. loadsection: @elf_arm_loadSection;
  875. encodeflags: @elf_arm_encodeflags;
  876. );
  877. as_arm_elf32_info : tasminfo =
  878. (
  879. id : as_arm_elf32;
  880. idtxt : 'ELF';
  881. asmbin : '';
  882. asmcmd : '';
  883. supported_targets : [system_arm_embedded,system_arm_darwin,
  884. system_arm_linux,system_arm_netbsd,
  885. system_arm_gba,system_arm_nds,
  886. system_arm_aros];
  887. flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf];
  888. labelprefix : '.L';
  889. comment : '';
  890. dollarsign: '$';
  891. );
  892. initialization
  893. RegisterAssembler(as_arm_elf32_info,TElfAssembler);
  894. ElfTarget:=elf_target_arm;
  895. ElfExeOutputClass:=TElfExeOutputARM;
  896. end.