arm-link.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #ifdef TARGET_DEFS_ONLY
  2. #define EM_TCC_TARGET EM_ARM
  3. /* relocation type for 32 bit data relocation */
  4. #define R_DATA_32 R_ARM_ABS32
  5. #define R_DATA_PTR R_ARM_ABS32
  6. #define R_JMP_SLOT R_ARM_JUMP_SLOT
  7. #define R_GLOB_DAT R_ARM_GLOB_DAT
  8. #define R_COPY R_ARM_COPY
  9. #define R_RELATIVE R_ARM_RELATIVE
  10. #define R_NUM R_ARM_NUM
  11. #define ELF_START_ADDR 0x00008000
  12. #define ELF_PAGE_SIZE 0x1000
  13. #define PCRELATIVE_DLLPLT 1
  14. #define RELOCATE_DLLPLT 0
  15. enum float_abi {
  16. ARM_SOFTFP_FLOAT,
  17. ARM_HARD_FLOAT,
  18. };
  19. #else /* !TARGET_DEFS_ONLY */
  20. #include "tcc.h"
  21. /* Returns 1 for a code relocation, 0 for a data relocation. For unknown
  22. relocations, returns -1. */
  23. int code_reloc (int reloc_type)
  24. {
  25. switch (reloc_type) {
  26. case R_ARM_MOVT_ABS:
  27. case R_ARM_MOVW_ABS_NC:
  28. case R_ARM_THM_MOVT_ABS:
  29. case R_ARM_THM_MOVW_ABS_NC:
  30. case R_ARM_ABS32:
  31. case R_ARM_REL32:
  32. case R_ARM_GOTPC:
  33. case R_ARM_GOTOFF:
  34. case R_ARM_GOT32:
  35. case R_ARM_COPY:
  36. case R_ARM_GLOB_DAT:
  37. case R_ARM_NONE:
  38. return 0;
  39. case R_ARM_PC24:
  40. case R_ARM_CALL:
  41. case R_ARM_JUMP24:
  42. case R_ARM_PLT32:
  43. case R_ARM_THM_PC22:
  44. case R_ARM_THM_JUMP24:
  45. case R_ARM_PREL31:
  46. case R_ARM_V4BX:
  47. case R_ARM_JUMP_SLOT:
  48. return 1;
  49. }
  50. tcc_error ("Unknown relocation type: %d", reloc_type);
  51. return -1;
  52. }
  53. /* Returns an enumerator to describe whether and when the relocation needs a
  54. GOT and/or PLT entry to be created. See tcc.h for a description of the
  55. different values. */
  56. int gotplt_entry_type (int reloc_type)
  57. {
  58. switch (reloc_type) {
  59. case R_ARM_NONE:
  60. case R_ARM_COPY:
  61. case R_ARM_GLOB_DAT:
  62. case R_ARM_JUMP_SLOT:
  63. return NO_GOTPLT_ENTRY;
  64. case R_ARM_PC24:
  65. case R_ARM_CALL:
  66. case R_ARM_JUMP24:
  67. case R_ARM_PLT32:
  68. case R_ARM_THM_PC22:
  69. case R_ARM_THM_JUMP24:
  70. case R_ARM_MOVT_ABS:
  71. case R_ARM_MOVW_ABS_NC:
  72. case R_ARM_THM_MOVT_ABS:
  73. case R_ARM_THM_MOVW_ABS_NC:
  74. case R_ARM_PREL31:
  75. case R_ARM_ABS32:
  76. case R_ARM_REL32:
  77. case R_ARM_V4BX:
  78. return AUTO_GOTPLT_ENTRY;
  79. case R_ARM_GOTPC:
  80. case R_ARM_GOTOFF:
  81. return BUILD_GOT_ONLY;
  82. case R_ARM_GOT32:
  83. return ALWAYS_GOTPLT_ENTRY;
  84. }
  85. tcc_error ("Unknown relocation type: %d", reloc_type);
  86. return -1;
  87. }
  88. ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_attr *attr)
  89. {
  90. Section *plt = s1->plt;
  91. uint8_t *p;
  92. unsigned plt_offset;
  93. /* when building a DLL, GOT entry accesses must be done relative to
  94. start of GOT (see x86_64 example above) */
  95. if (s1->output_type == TCC_OUTPUT_DLL)
  96. tcc_error("DLLs unimplemented!");
  97. /* empty PLT: create PLT0 entry that push address of call site and
  98. jump to ld.so resolution routine (GOT + 8) */
  99. if (plt->data_offset == 0) {
  100. p = section_ptr_add(plt, 20);
  101. write32le(p, 0xe52de004); /* push {lr} */
  102. write32le(p+4, 0xe59fe004); /* ldr lr, [pc, #4] */
  103. write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */
  104. write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
  105. /* p+16 is set in relocate_plt */
  106. }
  107. plt_offset = plt->data_offset;
  108. if (attr->plt_thumb_stub) {
  109. p = section_ptr_add(plt, 4);
  110. write32le(p, 0x4778); /* bx pc */
  111. write32le(p+2, 0x46c0); /* nop */
  112. }
  113. p = section_ptr_add(plt, 16);
  114. /* Jump to GOT entry where ld.so initially put address of PLT0 */
  115. write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
  116. write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
  117. write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
  118. /* p + 12 contains offset to GOT entry once patched by relocate_plt */
  119. write32le(p+12, got_offset);
  120. return plt_offset;
  121. }
  122. /* relocate the PLT: compute addresses and offsets in the PLT now that final
  123. address for PLT and GOT are known (see fill_program_header) */
  124. ST_FUNC void relocate_plt(TCCState *s1)
  125. {
  126. uint8_t *p, *p_end;
  127. if (!s1->plt)
  128. return;
  129. p = s1->plt->data;
  130. p_end = p + s1->plt->data_offset;
  131. if (p < p_end) {
  132. int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
  133. write32le(s1->plt->data + 16, x - 16);
  134. p += 20;
  135. while (p < p_end) {
  136. if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
  137. p += 4;
  138. add32le(p + 12, x + s1->plt->data - p);
  139. p += 16;
  140. }
  141. }
  142. }
  143. void relocate_init(Section *sr) {}
  144. void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
  145. {
  146. ElfW(Sym) *sym;
  147. int sym_index;
  148. sym_index = ELFW(R_SYM)(rel->r_info);
  149. sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
  150. switch(type) {
  151. case R_ARM_PC24:
  152. case R_ARM_CALL:
  153. case R_ARM_JUMP24:
  154. case R_ARM_PLT32:
  155. {
  156. int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko;
  157. x = (*(int *) ptr) & 0xffffff;
  158. #ifdef DEBUG_RELOC
  159. printf ("reloc %d: x=0x%x val=0x%x ", type, x, val);
  160. #endif
  161. (*(int *)ptr) &= 0xff000000;
  162. if (x & 0x800000)
  163. x -= 0x1000000;
  164. x <<= 2;
  165. blx_avail = (TCC_CPU_VERSION >= 5);
  166. is_thumb = val & 1;
  167. is_bl = (*(unsigned *) ptr) >> 24 == 0xeb;
  168. is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl));
  169. x += val - addr;
  170. #ifdef DEBUG_RELOC
  171. printf (" newx=0x%x name=%s\n", x,
  172. (char *) symtab_section->link->data + sym->st_name);
  173. #endif
  174. h = x & 2;
  175. th_ko = (x & 3) && (!blx_avail || !is_call);
  176. if (th_ko || x >= 0x2000000 || x < -0x2000000)
  177. tcc_error("can't relocate value at %x,%d",addr, type);
  178. x >>= 2;
  179. x &= 0xffffff;
  180. /* Only reached if blx is avail and it is a call */
  181. if (is_thumb) {
  182. x |= h << 24;
  183. (*(int *)ptr) = 0xfa << 24; /* bl -> blx */
  184. }
  185. (*(int *) ptr) |= x;
  186. }
  187. return;
  188. /* Since these relocations only concern Thumb-2 and blx instruction was
  189. introduced before Thumb-2, we can assume blx is available and not
  190. guard its use */
  191. case R_ARM_THM_PC22:
  192. case R_ARM_THM_JUMP24:
  193. {
  194. int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11;
  195. int to_thumb, is_call, to_plt, blx_bit = 1 << 12;
  196. Section *plt;
  197. /* weak reference */
  198. if (sym->st_shndx == SHN_UNDEF &&
  199. ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
  200. return;
  201. /* Get initial offset */
  202. hi = (*(uint16_t *)ptr);
  203. lo = (*(uint16_t *)(ptr+2));
  204. s = (hi >> 10) & 1;
  205. j1 = (lo >> 13) & 1;
  206. j2 = (lo >> 11) & 1;
  207. i1 = (j1 ^ s) ^ 1;
  208. i2 = (j2 ^ s) ^ 1;
  209. imm10 = hi & 0x3ff;
  210. imm11 = lo & 0x7ff;
  211. x = (s << 24) | (i1 << 23) | (i2 << 22) |
  212. (imm10 << 12) | (imm11 << 1);
  213. if (x & 0x01000000)
  214. x -= 0x02000000;
  215. /* Relocation infos */
  216. to_thumb = val & 1;
  217. plt = s1->plt;
  218. to_plt = (val >= plt->sh_addr) &&
  219. (val < plt->sh_addr + plt->data_offset);
  220. is_call = (type == R_ARM_THM_PC22);
  221. if (!to_thumb && !to_plt && !is_call) {
  222. int index;
  223. uint8_t *p;
  224. char *name, buf[1024];
  225. Section *text_section;
  226. name = (char *) symtab_section->link->data + sym->st_name;
  227. text_section = s1->sections[sym->st_shndx];
  228. /* Modify reloc to target a thumb stub to switch to ARM */
  229. snprintf(buf, sizeof(buf), "%s_from_thumb", name);
  230. index = put_elf_sym(symtab_section,
  231. text_section->data_offset + 1,
  232. sym->st_size, sym->st_info, 0,
  233. sym->st_shndx, buf);
  234. to_thumb = 1;
  235. val = text_section->data_offset + 1;
  236. rel->r_info = ELFW(R_INFO)(index, type);
  237. /* Create a thumb stub function to switch to ARM mode */
  238. put_elf_reloc(symtab_section, text_section,
  239. text_section->data_offset + 4, R_ARM_JUMP24,
  240. sym_index);
  241. p = section_ptr_add(text_section, 8);
  242. write32le(p, 0x4778); /* bx pc */
  243. write32le(p+2, 0x46c0); /* nop */
  244. write32le(p+4, 0xeafffffe); /* b $sym */
  245. }
  246. /* Compute final offset */
  247. x += val - addr;
  248. if (!to_thumb && is_call) {
  249. blx_bit = 0; /* bl -> blx */
  250. x = (x + 3) & -4; /* Compute offset from aligned PC */
  251. }
  252. /* Check that relocation is possible
  253. * offset must not be out of range
  254. * if target is to be entered in arm mode:
  255. - bit 1 must not set
  256. - instruction must be a call (bl) or a jump to PLT */
  257. if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
  258. if (to_thumb || (val & 2) || (!is_call && !to_plt))
  259. tcc_error("can't relocate value at %x,%d",addr, type);
  260. /* Compute and store final offset */
  261. s = (x >> 24) & 1;
  262. i1 = (x >> 23) & 1;
  263. i2 = (x >> 22) & 1;
  264. j1 = s ^ (i1 ^ 1);
  265. j2 = s ^ (i2 ^ 1);
  266. imm10 = (x >> 12) & 0x3ff;
  267. imm11 = (x >> 1) & 0x7ff;
  268. (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) |
  269. (s << 10) | imm10);
  270. (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) |
  271. (j1 << 13) | blx_bit | (j2 << 11) |
  272. imm11);
  273. }
  274. return;
  275. case R_ARM_MOVT_ABS:
  276. case R_ARM_MOVW_ABS_NC:
  277. {
  278. int x, imm4, imm12;
  279. if (type == R_ARM_MOVT_ABS)
  280. val >>= 16;
  281. imm12 = val & 0xfff;
  282. imm4 = (val >> 12) & 0xf;
  283. x = (imm4 << 16) | imm12;
  284. if (type == R_ARM_THM_MOVT_ABS)
  285. *(int *)ptr |= x;
  286. else
  287. *(int *)ptr += x;
  288. }
  289. return;
  290. case R_ARM_THM_MOVT_ABS:
  291. case R_ARM_THM_MOVW_ABS_NC:
  292. {
  293. int x, i, imm4, imm3, imm8;
  294. if (type == R_ARM_THM_MOVT_ABS)
  295. val >>= 16;
  296. imm8 = val & 0xff;
  297. imm3 = (val >> 8) & 0x7;
  298. i = (val >> 11) & 1;
  299. imm4 = (val >> 12) & 0xf;
  300. x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4;
  301. if (type == R_ARM_THM_MOVT_ABS)
  302. *(int *)ptr |= x;
  303. else
  304. *(int *)ptr += x;
  305. }
  306. return;
  307. case R_ARM_PREL31:
  308. {
  309. int x;
  310. x = (*(int *)ptr) & 0x7fffffff;
  311. (*(int *)ptr) &= 0x80000000;
  312. x = (x * 2) / 2;
  313. x += val - addr;
  314. if((x^(x>>1))&0x40000000)
  315. tcc_error("can't relocate value at %x,%d",addr, type);
  316. (*(int *)ptr) |= x & 0x7fffffff;
  317. }
  318. case R_ARM_ABS32:
  319. *(int *)ptr += val;
  320. return;
  321. case R_ARM_REL32:
  322. *(int *)ptr += val - addr;
  323. return;
  324. case R_ARM_GOTPC:
  325. *(int *)ptr += s1->got->sh_addr - addr;
  326. return;
  327. case R_ARM_GOTOFF:
  328. *(int *)ptr += val - s1->got->sh_addr;
  329. return;
  330. case R_ARM_GOT32:
  331. /* we load the got offset */
  332. *(int *)ptr += s1->sym_attrs[sym_index].got_offset;
  333. return;
  334. case R_ARM_COPY:
  335. return;
  336. case R_ARM_V4BX:
  337. /* trade Thumb support for ARMv4 support */
  338. if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10)
  339. *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
  340. return;
  341. case R_ARM_GLOB_DAT:
  342. case R_ARM_JUMP_SLOT:
  343. *(addr_t *)ptr = val;
  344. return;
  345. case R_ARM_NONE:
  346. /* Nothing to do. Normally used to indicate a dependency
  347. on a certain symbol (like for exception handling under EABI). */
  348. return;
  349. default:
  350. fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n",
  351. type, (unsigned)addr, ptr, (unsigned)val);
  352. return;
  353. }
  354. }
  355. #endif /* !TARGET_DEFS_ONLY */