elf32-d30v.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /* D30V-specific support for 32-bit ELF
  2. Copyright (C) 1997-2022 Free Software Foundation, Inc.
  3. Contributed by Martin Hunt (hunt@cygnus.com).
  4. This file is part of BFD, the Binary File Descriptor library.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. MA 02110-1301, USA. */
  17. #include "sysdep.h"
  18. #include "bfd.h"
  19. #include "libbfd.h"
  20. #include "elf-bfd.h"
  21. #include "elf/d30v.h"
  22. #define MAX32 ((bfd_signed_vma) 0x7fffffff)
  23. #define MIN32 (- MAX32 - 1)
  24. static bfd_reloc_status_type
  25. bfd_elf_d30v_reloc (bfd *abfd,
  26. arelent *reloc_entry,
  27. asymbol *symbol,
  28. void * data,
  29. asection *input_section,
  30. bfd *output_bfd,
  31. char **error_message)
  32. {
  33. bfd_signed_vma relocation;
  34. bfd_vma in1, in2, num;
  35. bfd_vma tmp_addr = 0;
  36. bfd_reloc_status_type r;
  37. asection *reloc_target_output_section;
  38. bfd_size_type addr = reloc_entry->address;
  39. bfd_reloc_status_type flag = bfd_reloc_ok;
  40. bfd_vma output_base = 0;
  41. reloc_howto_type *howto = reloc_entry->howto;
  42. int make_absolute = 0;
  43. if (output_bfd != NULL)
  44. {
  45. /* Partial linking -- do nothing. */
  46. reloc_entry->address += input_section->output_offset;
  47. return bfd_reloc_ok;
  48. }
  49. r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
  50. input_section, output_bfd, error_message);
  51. if (r != bfd_reloc_continue)
  52. return r;
  53. /* A hacked-up version of bfd_perform_reloc() follows. */
  54. if (bfd_is_und_section (symbol->section)
  55. && (symbol->flags & BSF_WEAK) == 0
  56. && output_bfd == NULL)
  57. flag = bfd_reloc_undefined;
  58. /* Is the address of the relocation really within the section? */
  59. if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
  60. return bfd_reloc_outofrange;
  61. /* Work out which section the relocation is targeted at and the
  62. initial relocation command value. */
  63. /* Get symbol value. (Common symbols are special.) */
  64. if (bfd_is_com_section (symbol->section))
  65. relocation = 0;
  66. else
  67. relocation = symbol->value;
  68. reloc_target_output_section = symbol->section->output_section;
  69. /* Convert input-section-relative symbol value to absolute. */
  70. output_base = reloc_target_output_section->vma;
  71. relocation += output_base + symbol->section->output_offset;
  72. /* Add in supplied addend. */
  73. relocation += reloc_entry->addend;
  74. /* Here the variable relocation holds the final address of the
  75. symbol we are relocating against, plus any addend. */
  76. if (howto->pc_relative)
  77. {
  78. tmp_addr = input_section->output_section->vma
  79. + input_section->output_offset
  80. + reloc_entry->address;
  81. relocation -= tmp_addr;
  82. }
  83. in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
  84. in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
  85. /* Extract the addend. */
  86. num = ((in2 & 0x3FFFF)
  87. | ((in2 & 0xFF00000) >> 2)
  88. | ((in1 & 0x3F) << 26));
  89. in1 &= 0xFFFFFFC0;
  90. in2 = 0x80000000;
  91. relocation += num;
  92. if (howto->pc_relative && howto->bitsize == 32)
  93. {
  94. /* The D30V has a PC that doesn't wrap and PC-relative jumps are
  95. signed, so a PC-relative jump can't be more than +/- 2^31 bytes.
  96. If one exceeds this, change it to an absolute jump. */
  97. if (relocation > MAX32 || relocation < MIN32)
  98. {
  99. relocation = (relocation + tmp_addr) & 0xffffffff;
  100. make_absolute = 1;
  101. }
  102. }
  103. in1 |= (relocation >> 26) & 0x3F; /* Top 6 bits. */
  104. in2 |= ((relocation & 0x03FC0000) << 2); /* Next 8 bits. */
  105. in2 |= relocation & 0x0003FFFF; /* Bottom 18 bits. */
  106. /* Change a PC-relative instruction to its
  107. absolute equivalent with this simple hack. */
  108. if (make_absolute)
  109. in1 |= 0x00100000;
  110. bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
  111. bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
  112. return flag;
  113. }
  114. static bfd_reloc_status_type
  115. bfd_elf_d30v_reloc_21 (bfd *abfd,
  116. arelent *reloc_entry,
  117. asymbol *symbol,
  118. void * data,
  119. asection *input_section,
  120. bfd *output_bfd,
  121. char **error_message)
  122. {
  123. bfd_vma relocation;
  124. bfd_vma in1, num;
  125. bfd_reloc_status_type r;
  126. asection *reloc_target_output_section;
  127. bfd_size_type addr = reloc_entry->address;
  128. bfd_reloc_status_type flag = bfd_reloc_ok;
  129. bfd_vma output_base = 0;
  130. reloc_howto_type *howto = reloc_entry->howto;
  131. int mask, max;
  132. if (output_bfd != NULL)
  133. {
  134. /* Partial linking -- do nothing. */
  135. reloc_entry->address += input_section->output_offset;
  136. return bfd_reloc_ok;
  137. }
  138. r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
  139. input_section, output_bfd, error_message);
  140. if (r != bfd_reloc_continue)
  141. return r;
  142. /* A hacked-up version of bfd_perform_reloc() follows. */
  143. if (bfd_is_und_section (symbol->section)
  144. && (symbol->flags & BSF_WEAK) == 0
  145. && output_bfd == NULL)
  146. flag = bfd_reloc_undefined;
  147. /* Is the address of the relocation really within the section? */
  148. if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
  149. return bfd_reloc_outofrange;
  150. /* Work out which section the relocation is targeted at and the
  151. initial relocation command value. */
  152. /* Get symbol value. (Common symbols are special.) */
  153. if (bfd_is_com_section (symbol->section))
  154. relocation = 0;
  155. else
  156. relocation = symbol->value;
  157. reloc_target_output_section = symbol->section->output_section;
  158. /* Convert input-section-relative symbol value to absolute. */
  159. output_base = reloc_target_output_section->vma;
  160. relocation += output_base + symbol->section->output_offset;
  161. /* Add in supplied addend. */
  162. relocation += reloc_entry->addend;
  163. /* Here the variable relocation holds the final address of the
  164. symbol we are relocating against, plus any addend. */
  165. if (howto->pc_relative)
  166. {
  167. relocation -= (input_section->output_section->vma
  168. + input_section->output_offset);
  169. if (howto->pcrel_offset)
  170. relocation -= reloc_entry->address;
  171. }
  172. in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
  173. mask = (1 << howto->bitsize) - 1;
  174. if (howto->bitsize == 6)
  175. mask <<= 12;
  176. max = (1 << (howto->bitsize + 2)) - 1;
  177. /* Extract the addend. */
  178. num = in1 & mask; /* 18 bits. */
  179. if (howto->bitsize == 6)
  180. num >>= 12;
  181. num <<= 3; /* shift left 3. */
  182. in1 &= ~mask; /* Mask out addend. */
  183. relocation += num;
  184. if (howto->type == R_D30V_21_PCREL_R
  185. || howto->type == R_D30V_15_PCREL_R
  186. || howto->type == R_D30V_9_PCREL_R)
  187. relocation += 4;
  188. if ((int) relocation < 0)
  189. {
  190. if (~ (int) relocation > max)
  191. flag = bfd_reloc_overflow;
  192. }
  193. else
  194. {
  195. if ((int) relocation > max)
  196. flag = bfd_reloc_overflow;
  197. }
  198. relocation >>= 3;
  199. if (howto->bitsize == 6)
  200. in1 |= ((relocation & (mask >> 12)) << 12);
  201. else
  202. in1 |= relocation & mask;
  203. bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
  204. return flag;
  205. }
  206. static reloc_howto_type elf_d30v_howto_table[] =
  207. {
  208. /* This reloc does nothing. */
  209. HOWTO (R_D30V_NONE, /* Type. */
  210. 0, /* Rightshift. */
  211. 3, /* Size (0 = byte, 1 = short, 2 = long). */
  212. 0, /* Bitsize. */
  213. false, /* PC_relative. */
  214. 0, /* Bitpos. */
  215. complain_overflow_dont, /* Complain_on_overflow. */
  216. bfd_elf_generic_reloc, /* Special_function. */
  217. "R_D30V_NONE", /* Name. */
  218. false, /* Partial_inplace. */
  219. 0, /* Src_mask. */
  220. 0, /* Dst_mask. */
  221. false), /* PCrel_offset. */
  222. /* A 6 bit absolute relocation. */
  223. HOWTO (R_D30V_6, /* Type. */
  224. 0, /* Rightshift. */
  225. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  226. 6, /* Bitsize. */
  227. false, /* PC_relative. */
  228. 0, /* Bitpos. */
  229. complain_overflow_bitfield, /* Complain_on_overflow. */
  230. bfd_elf_generic_reloc, /* Special_function. */
  231. "R_D30V_6", /* Name. */
  232. false, /* Partial_inplace. */
  233. 0x3f, /* Src_mask. */
  234. 0x3f, /* Dst_mask. */
  235. false), /* PCrel_offset. */
  236. /* A relative 9 bit relocation, right shifted by 3. */
  237. HOWTO (R_D30V_9_PCREL, /* Type. */
  238. 3, /* Rightshift. */
  239. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  240. 6, /* Bitsize. */
  241. true, /* PC_relative. */
  242. 0, /* Bitpos. */
  243. complain_overflow_signed, /* Complain_on_overflow. */
  244. bfd_elf_d30v_reloc_21, /* Special_function. */
  245. "R_D30V_9_PCREL", /* Name. */
  246. false, /* Partial_inplace. */
  247. 0x3f, /* Src_mask. */
  248. 0x3f, /* Dst_mask. */
  249. true), /* PCrel_offset. */
  250. /* A relative 9 bit relocation, right shifted by 3. */
  251. HOWTO (R_D30V_9_PCREL_R, /* Type. */
  252. 3, /* Rightshift. */
  253. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  254. 6, /* Bitsize. */
  255. true, /* PC_relative. */
  256. 0, /* Bitpos. */
  257. complain_overflow_signed, /* Complain_on_overflow. */
  258. bfd_elf_d30v_reloc_21, /* Special_function. */
  259. "R_D30V_9_PCREL_R", /* Name. */
  260. false, /* Partial_inplace. */
  261. 0x3f, /* Src_mask. */
  262. 0x3f, /* Dst_mask. */
  263. true), /* PCrel_offset. */
  264. /* An absolute 15 bit relocation, right shifted by 3. */
  265. HOWTO (R_D30V_15, /* Type. */
  266. 3, /* Rightshift. */
  267. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  268. 12, /* Bitsize. */
  269. false, /* PC_relative. */
  270. 0, /* Bitpos. */
  271. complain_overflow_signed, /* Complain_on_overflow. */
  272. bfd_elf_generic_reloc, /* Special_function. */
  273. "R_D30V_15", /* Name. */
  274. false, /* Partial_inplace. */
  275. 0xfff, /* Src_mask. */
  276. 0xfff, /* Dst_mask. */
  277. false), /* PCrel_offset. */
  278. /* A relative 15 bit relocation, right shifted by 3. */
  279. HOWTO (R_D30V_15_PCREL, /* Type. */
  280. 3, /* Rightshift. */
  281. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  282. 12, /* Bitsize. */
  283. true, /* PC_relative. */
  284. 0, /* Bitpos. */
  285. complain_overflow_signed, /* Complain_on_overflow. */
  286. bfd_elf_d30v_reloc_21, /* Special_function. */
  287. "R_D30V_15_PCREL", /* Name. */
  288. false, /* Partial_inplace. */
  289. 0xfff, /* Src_mask. */
  290. 0xfff, /* Dst_mask. */
  291. true), /* PCrel_offset. */
  292. /* A relative 15 bit relocation, right shifted by 3. */
  293. HOWTO (R_D30V_15_PCREL_R, /* Type. */
  294. 3, /* Rightshift. */
  295. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  296. 12, /* Bitsize. */
  297. true, /* PC_relative. */
  298. 0, /* Bitpos. */
  299. complain_overflow_signed, /* Complain_on_overflow. */
  300. bfd_elf_d30v_reloc_21, /* Special_function. */
  301. "R_D30V_15_PCREL_R", /* Name. */
  302. false, /* Partial_inplace. */
  303. 0xfff, /* Src_mask. */
  304. 0xfff, /* Dst_mask. */
  305. true), /* PCrel_offset. */
  306. /* An absolute 21 bit relocation, right shifted by 3. */
  307. HOWTO (R_D30V_21, /* Type. */
  308. 3, /* Rightshift. */
  309. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  310. 18, /* Bitsize. */
  311. false, /* PC_relative. */
  312. 0, /* Bitpos. */
  313. complain_overflow_signed, /* Complain_on_overflow. */
  314. bfd_elf_generic_reloc, /* Special_function. */
  315. "R_D30V_21", /* Name. */
  316. false, /* Partial_inplace. */
  317. 0x3ffff, /* Src_mask. */
  318. 0x3ffff, /* Dst_mask. */
  319. false), /* PCrel_offset. */
  320. /* A relative 21 bit relocation, right shifted by 3. */
  321. HOWTO (R_D30V_21_PCREL, /* Type. */
  322. 3, /* Rightshift. */
  323. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  324. 18, /* Bitsize. */
  325. true, /* PC_relative. */
  326. 0, /* Bitpos. */
  327. complain_overflow_signed, /* Complain_on_overflow. */
  328. bfd_elf_d30v_reloc_21, /* Special_function. */
  329. "R_D30V_21_PCREL", /* Name. */
  330. false, /* Partial_inplace. */
  331. 0x3ffff, /* Src_mask. */
  332. 0x3ffff, /* Dst_mask. */
  333. true), /* PCrel_offset. */
  334. /* A relative 21 bit relocation, right shifted by 3, in the Right container. */
  335. HOWTO (R_D30V_21_PCREL_R, /* Type. */
  336. 3, /* Rightshift. */
  337. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  338. 18, /* Bitsize. */
  339. true, /* PC_relative. */
  340. 0, /* Bitpos. */
  341. complain_overflow_signed, /* Complain_on_overflow. */
  342. bfd_elf_d30v_reloc_21, /* Special_function. */
  343. "R_D30V_21_PCREL_R", /* Name. */
  344. false, /* Partial_inplace. */
  345. 0x3ffff, /* Src_mask. */
  346. 0x3ffff, /* Dst_mask. */
  347. true), /* PCrel_offset. */
  348. /* A D30V 32 bit absolute relocation. */
  349. HOWTO (R_D30V_32, /* Type. */
  350. 0, /* Rightshift. */
  351. 4, /* Size (0 = byte, 1 = short, 2 = long). */
  352. 32, /* Bitsize. */
  353. false, /* PC_relative. */
  354. 0, /* Bitpos. */
  355. complain_overflow_bitfield, /* Complain_on_overflow. */
  356. bfd_elf_d30v_reloc, /* Special_function. */
  357. "R_D30V_32", /* Name. */
  358. false, /* Partial_inplace. */
  359. 0xffffffff, /* Src_mask. */
  360. 0xffffffff, /* Dst_mask. */
  361. false), /* PCrel_offset. */
  362. /* A relative 32 bit relocation. */
  363. HOWTO (R_D30V_32_PCREL, /* Type. */
  364. 0, /* Rightshift. */
  365. 4, /* Size (0 = byte, 1 = short, 2 = long). */
  366. 32, /* Bitsize. */
  367. true, /* PC_relative. */
  368. 0, /* Bitpos. */
  369. complain_overflow_signed, /* Complain_on_overflow. */
  370. bfd_elf_d30v_reloc, /* Special_function. */
  371. "R_D30V_32_PCREL", /* Name. */
  372. false, /* Partial_inplace. */
  373. 0xffffffff, /* Src_mask. */
  374. 0xffffffff, /* Dst_mask. */
  375. true), /* PCrel_offset. */
  376. /* A regular 32 bit absolute relocation. */
  377. HOWTO (R_D30V_32_NORMAL, /* Type. */
  378. 0, /* Rightshift. */
  379. 2, /* Size (0 = byte, 1 = short, 2 = long). */
  380. 32, /* Bitsize. */
  381. false, /* PC_relative. */
  382. 0, /* Bitpos. */
  383. complain_overflow_bitfield, /* Complain_on_overflow. */
  384. bfd_elf_generic_reloc, /* Special_function. */
  385. "R_D30V_32_NORMAL", /* Name. */
  386. false, /* Partial_inplace. */
  387. 0xffffffff, /* Src_mask. */
  388. 0xffffffff, /* Dst_mask. */
  389. false), /* PCrel_offset. */
  390. };
  391. /* Map BFD reloc types to D30V ELF reloc types. */
  392. struct d30v_reloc_map
  393. {
  394. bfd_reloc_code_real_type bfd_reloc_val;
  395. unsigned char elf_reloc_val;
  396. };
  397. static const struct d30v_reloc_map d30v_reloc_map[] =
  398. {
  399. { BFD_RELOC_NONE, R_D30V_NONE, },
  400. { BFD_RELOC_D30V_6, R_D30V_6 },
  401. { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL },
  402. { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R },
  403. { BFD_RELOC_D30V_15, R_D30V_15 },
  404. { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
  405. { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R },
  406. { BFD_RELOC_D30V_21, R_D30V_21 },
  407. { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
  408. { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R },
  409. { BFD_RELOC_D30V_32, R_D30V_32 },
  410. { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
  411. { BFD_RELOC_32, R_D30V_32_NORMAL },
  412. };
  413. static reloc_howto_type *
  414. bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  415. bfd_reloc_code_real_type code)
  416. {
  417. unsigned int i;
  418. for (i = 0;
  419. i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
  420. i++)
  421. {
  422. if (d30v_reloc_map[i].bfd_reloc_val == code)
  423. return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
  424. }
  425. return NULL;
  426. }
  427. static reloc_howto_type *
  428. bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  429. const char *r_name)
  430. {
  431. unsigned int i;
  432. for (i = 0;
  433. i < sizeof (elf_d30v_howto_table) / sizeof (elf_d30v_howto_table[0]);
  434. i++)
  435. if (elf_d30v_howto_table[i].name != NULL
  436. && strcasecmp (elf_d30v_howto_table[i].name, r_name) == 0)
  437. return &elf_d30v_howto_table[i];
  438. return NULL;
  439. }
  440. /* Set the howto pointer for an D30V ELF reloc (type REL). */
  441. static bool
  442. d30v_info_to_howto_rel (bfd *abfd,
  443. arelent *cache_ptr,
  444. Elf_Internal_Rela *dst)
  445. {
  446. unsigned int r_type;
  447. r_type = ELF32_R_TYPE (dst->r_info);
  448. if (r_type >= (unsigned int) R_D30V_max)
  449. {
  450. /* xgettext:c-format */
  451. _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
  452. abfd, r_type);
  453. bfd_set_error (bfd_error_bad_value);
  454. return false;
  455. }
  456. cache_ptr->howto = &elf_d30v_howto_table[r_type];
  457. return true;
  458. }
  459. /* Set the howto pointer for an D30V ELF reloc (type RELA). */
  460. static bool
  461. d30v_info_to_howto_rela (bfd *abfd,
  462. arelent *cache_ptr,
  463. Elf_Internal_Rela *dst)
  464. {
  465. unsigned int r_type;
  466. r_type = ELF32_R_TYPE (dst->r_info);
  467. if (r_type >= (unsigned int) R_D30V_max)
  468. {
  469. /* xgettext:c-format */
  470. _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
  471. abfd, r_type);
  472. bfd_set_error (bfd_error_bad_value);
  473. return false;
  474. }
  475. cache_ptr->howto = &elf_d30v_howto_table[r_type];
  476. return true;
  477. }
  478. #define ELF_ARCH bfd_arch_d30v
  479. #define ELF_MACHINE_CODE EM_D30V
  480. #define ELF_MACHINE_ALT1 EM_CYGNUS_D30V
  481. #define ELF_MAXPAGESIZE 0x1000
  482. #define TARGET_BIG_SYM d30v_elf32_vec
  483. #define TARGET_BIG_NAME "elf32-d30v"
  484. #define elf_info_to_howto d30v_info_to_howto_rela
  485. #define elf_info_to_howto_rel d30v_info_to_howto_rel
  486. #define elf_backend_object_p 0
  487. #include "elf32-target.h"