coff-z80.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /* BFD back-end for Zilog Z80 COFF binaries.
  2. Copyright (C) 2005-2022 Free Software Foundation, Inc.
  3. Contributed by Arnold Metselaar <arnold_m@operamail.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 "bfdlink.h"
  21. #include "coff/z80.h"
  22. #include "coff/internal.h"
  23. #include "libcoff.h"
  24. #include "libiberty.h"
  25. #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
  26. typedef const struct {
  27. bfd_reloc_code_real_type r_type;
  28. reloc_howto_type howto;
  29. } bfd_howto_type;
  30. #define BFD_EMPTY_HOWTO(rt,x) {rt, EMPTY_HOWTO(x)}
  31. #define BFD_HOWTO(rt,a,b,c,d,e,f,g,h,i,j,k,l,m) {rt, HOWTO(a,b,c,d,e,f,g,h,i,j,k,l,m)}
  32. static bfd_howto_type howto_table[] =
  33. {
  34. BFD_EMPTY_HOWTO (BFD_RELOC_NONE, 0),
  35. BFD_HOWTO (BFD_RELOC_32,
  36. R_IMM32, /* type */
  37. 0, /* rightshift */
  38. 2, /* size (0 = byte, 1 = short, 2 = long) */
  39. 32, /* bitsize */
  40. false, /* pc_relative */
  41. 0, /* bitpos */
  42. complain_overflow_bitfield, /* complain_on_overflow */
  43. 0, /* special_function */
  44. "r_imm32", /* name */
  45. false, /* partial_inplace */
  46. 0xffffffff, /* src_mask */
  47. 0xffffffff, /* dst_mask */
  48. false), /* pcrel_offset */
  49. BFD_HOWTO (BFD_RELOC_24,
  50. R_IMM24, /* type */
  51. 0, /* rightshift */
  52. 1, /* size (0 = byte, 1 = short, 2 = long) */
  53. 24, /* bitsize */
  54. false, /* pc_relative */
  55. 0, /* bitpos */
  56. complain_overflow_bitfield, /* complain_on_overflow */
  57. 0, /* special_function */
  58. "r_imm24", /* name */
  59. false, /* partial_inplace */
  60. 0x00ffffff, /* src_mask */
  61. 0x00ffffff, /* dst_mask */
  62. false), /* pcrel_offset */
  63. BFD_HOWTO (BFD_RELOC_16,
  64. R_IMM16, /* type */
  65. 0, /* rightshift */
  66. 1, /* size (0 = byte, 1 = short, 2 = long) */
  67. 16, /* bitsize */
  68. false, /* pc_relative */
  69. 0, /* bitpos */
  70. complain_overflow_bitfield, /* complain_on_overflow */
  71. 0, /* special_function */
  72. "r_imm16", /* name */
  73. false, /* partial_inplace */
  74. 0x0000ffff, /* src_mask */
  75. 0x0000ffff, /* dst_mask */
  76. false), /* pcrel_offset */
  77. BFD_HOWTO (BFD_RELOC_8,
  78. R_IMM8, /* type */
  79. 0, /* rightshift */
  80. 0, /* size (0 = byte, 1 = short, 2 = long) */
  81. 8, /* bitsize */
  82. false, /* pc_relative */
  83. 0, /* bitpos */
  84. complain_overflow_bitfield, /* complain_on_overflow */
  85. 0, /* special_function */
  86. "r_imm8", /* name */
  87. false, /* partial_inplace */
  88. 0x000000ff, /* src_mask */
  89. 0x000000ff, /* dst_mask */
  90. false), /* pcrel_offset */
  91. BFD_HOWTO (BFD_RELOC_8_PCREL,
  92. R_JR, /* type */
  93. 0, /* rightshift */
  94. 0, /* size (0 = byte, 1 = short, 2 = long) */
  95. 8, /* bitsize */
  96. true, /* pc_relative */
  97. 0, /* bitpos */
  98. complain_overflow_signed, /* complain_on_overflow */
  99. 0, /* special_function */
  100. "r_jr", /* name */
  101. false, /* partial_inplace */
  102. 0, /* src_mask */
  103. 0xFF, /* dst_mask */
  104. true), /* pcrel_offset */
  105. BFD_HOWTO (BFD_RELOC_Z80_DISP8,
  106. R_OFF8, /* type */
  107. 0, /* rightshift */
  108. 0, /* size (0 = byte, 1 = short, 2 = long) */
  109. 8, /* bitsize */
  110. false, /* pc_relative */
  111. 0, /* bitpos */
  112. complain_overflow_signed, /* complain_on_overflow */
  113. 0, /* special_function */
  114. "r_off8", /* name */
  115. false, /* partial_inplace */
  116. 0, /* src_mask */
  117. 0xff, /* dst_mask */
  118. false), /* pcrel_offset */
  119. BFD_HOWTO (BFD_RELOC_Z80_BYTE0,
  120. R_BYTE0, /* type */
  121. 0, /* rightshift */
  122. 0, /* size (0 = byte, 1 = short, 2 = long) */
  123. 8, /* bitsize */
  124. false, /* pc_relative */
  125. 0, /* bitpos */
  126. complain_overflow_dont, /* complain_on_overflow */
  127. 0, /* special_function */
  128. "r_byte0", /* name */
  129. false, /* partial_inplace */
  130. 0, /* src_mask */
  131. 0xff, /* dst_mask */
  132. false), /* pcrel_offset */
  133. BFD_HOWTO (BFD_RELOC_Z80_BYTE1,
  134. R_BYTE1, /* type */
  135. 8, /* rightshift */
  136. 0, /* size (0 = byte, 1 = short, 2 = long) */
  137. 8, /* bitsize */
  138. false, /* pc_relative */
  139. 0, /* bitpos */
  140. complain_overflow_dont, /* complain_on_overflow */
  141. 0, /* special_function */
  142. "r_byte1", /* name */
  143. false, /* partial_inplace */
  144. 0, /* src_mask */
  145. 0xff, /* dst_mask */
  146. false), /* pcrel_offset */
  147. BFD_HOWTO (BFD_RELOC_Z80_BYTE2,
  148. R_BYTE2, /* type */
  149. 16, /* rightshift */
  150. 0, /* size (0 = byte, 1 = short, 2 = long) */
  151. 8, /* bitsize */
  152. false, /* pc_relative */
  153. 0, /* bitpos */
  154. complain_overflow_dont, /* complain_on_overflow */
  155. 0, /* special_function */
  156. "r_byte2", /* name */
  157. false, /* partial_inplace */
  158. 0, /* src_mask */
  159. 0xff, /* dst_mask */
  160. false), /* pcrel_offset */
  161. BFD_HOWTO (BFD_RELOC_Z80_BYTE3,
  162. R_BYTE3, /* type */
  163. 24, /* rightshift */
  164. 0, /* size (0 = byte, 1 = short, 2 = long) */
  165. 8, /* bitsize */
  166. false, /* pc_relative */
  167. 0, /* bitpos */
  168. complain_overflow_dont, /* complain_on_overflow */
  169. 0, /* special_function */
  170. "r_byte3", /* name */
  171. false, /* partial_inplace */
  172. 0, /* src_mask */
  173. 0xff, /* dst_mask */
  174. false), /* pcrel_offset */
  175. BFD_HOWTO (BFD_RELOC_Z80_WORD0,
  176. R_WORD0, /* type */
  177. 0, /* rightshift */
  178. 0, /* size (0 = byte, 1 = short, 2 = long) */
  179. 16, /* bitsize */
  180. false, /* pc_relative */
  181. 0, /* bitpos */
  182. complain_overflow_dont, /* complain_on_overflow */
  183. 0, /* special_function */
  184. "r_word0", /* name */
  185. false, /* partial_inplace */
  186. 0, /* src_mask */
  187. 0xffff, /* dst_mask */
  188. false), /* pcrel_offset */
  189. BFD_HOWTO (BFD_RELOC_Z80_WORD1,
  190. R_WORD1, /* type */
  191. 16, /* rightshift */
  192. 0, /* size (0 = byte, 1 = short, 2 = long) */
  193. 16, /* bitsize */
  194. false, /* pc_relative */
  195. 0, /* bitpos */
  196. complain_overflow_dont, /* complain_on_overflow */
  197. 0, /* special_function */
  198. "r_word1", /* name */
  199. false, /* partial_inplace */
  200. 0, /* src_mask */
  201. 0xffff, /* dst_mask */
  202. false), /* pcrel_offset */
  203. BFD_HOWTO (BFD_RELOC_Z80_16_BE,
  204. R_IMM16BE, /* type */
  205. 0, /* rightshift */
  206. 1, /* size (0 = byte, 1 = short, 2 = long) */
  207. 16, /* bitsize */
  208. false, /* pc_relative */
  209. 0, /* bitpos */
  210. complain_overflow_bitfield, /* complain_on_overflow */
  211. 0, /* special_function */
  212. "r_imm16be", /* name */
  213. false, /* partial_inplace */
  214. 0x0000ffff, /* src_mask */
  215. 0x0000ffff, /* dst_mask */
  216. false), /* pcrel_offset */
  217. };
  218. #define NUM_HOWTOS ARRAY_SIZE (howto_table)
  219. #define BADMAG(x) Z80BADMAG(x)
  220. #define Z80 1 /* Customize coffcode.h. */
  221. #define __A_MAGIC_SET__
  222. /* Code to swap in the reloc. */
  223. #define SWAP_IN_RELOC_OFFSET H_GET_32
  224. #define SWAP_OUT_RELOC_OFFSET H_PUT_32
  225. #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
  226. dst->r_stuff[0] = 'S'; \
  227. dst->r_stuff[1] = 'C';
  228. /* Code to turn a r_type into a howto ptr, uses the above howto table. */
  229. static void
  230. rtype2howto (arelent *internal, struct internal_reloc *dst)
  231. {
  232. unsigned i;
  233. for (i = 0; i < NUM_HOWTOS; i++)
  234. {
  235. if (howto_table[i].howto.type == dst->r_type)
  236. {
  237. internal->howto = &howto_table[i].howto;
  238. return;
  239. }
  240. }
  241. internal->howto = NULL;
  242. }
  243. #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
  244. static reloc_howto_type *
  245. coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  246. bfd_reloc_code_real_type code)
  247. {
  248. unsigned i;
  249. for (i = 0; i < NUM_HOWTOS; i++)
  250. if (howto_table[i].r_type == code)
  251. return &howto_table[i].howto;
  252. BFD_FAIL ();
  253. return NULL;
  254. }
  255. static reloc_howto_type *
  256. coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  257. const char *r_name)
  258. {
  259. unsigned i;
  260. for (i = 0; i < NUM_HOWTOS; i++)
  261. if (strcasecmp(howto_table[i].howto.name, r_name) == 0)
  262. return &howto_table[i].howto;
  263. return NULL;
  264. }
  265. /* Perform any necessary magic to the addend in a reloc entry. */
  266. #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
  267. cache_ptr->addend = ext_reloc.r_offset;
  268. #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
  269. reloc_processing(relent, reloc, symbols, abfd, section)
  270. static void
  271. reloc_processing (arelent *relent,
  272. struct internal_reloc *reloc,
  273. asymbol **symbols,
  274. bfd *abfd,
  275. asection *section)
  276. {
  277. relent->address = reloc->r_vaddr;
  278. rtype2howto (relent, reloc);
  279. if (reloc->r_symndx == -1)
  280. relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
  281. else if (reloc->r_symndx >= 0 && reloc->r_symndx < obj_conv_table_size (abfd))
  282. relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
  283. else
  284. {
  285. _bfd_error_handler
  286. /* xgettext:c-format */
  287. (_("%pB: warning: illegal symbol index %ld in relocs"),
  288. abfd, reloc->r_symndx);
  289. relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
  290. }
  291. relent->addend = reloc->r_offset;
  292. relent->address -= section->vma;
  293. }
  294. static void
  295. extra_case (bfd *in_abfd,
  296. struct bfd_link_info *link_info,
  297. struct bfd_link_order *link_order,
  298. arelent *reloc,
  299. bfd_byte *data,
  300. unsigned int *src_ptr,
  301. unsigned int *dst_ptr)
  302. {
  303. asection * input_section = link_order->u.indirect.section;
  304. int val = bfd_coff_reloc16_get_value (reloc, link_info, input_section);
  305. switch (reloc->howto->type)
  306. {
  307. case R_OFF8:
  308. if (reloc->howto->partial_inplace)
  309. val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
  310. & reloc->howto->src_mask);
  311. if (val>127 || val<-128) /* Test for overflow. */
  312. (*link_info->callbacks->reloc_overflow)
  313. (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
  314. reloc->howto->name, reloc->addend, input_section->owner,
  315. input_section, reloc->address);
  316. bfd_put_8 (in_abfd, val, data + *dst_ptr);
  317. (*dst_ptr) += 1;
  318. (*src_ptr) += 1;
  319. break;
  320. case R_BYTE3:
  321. bfd_put_8 (in_abfd, val >> 24, data + *dst_ptr);
  322. (*dst_ptr) += 1;
  323. (*src_ptr) += 1;
  324. break;
  325. case R_BYTE2:
  326. bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr);
  327. (*dst_ptr) += 1;
  328. (*src_ptr) += 1;
  329. break;
  330. case R_BYTE1:
  331. bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr);
  332. (*dst_ptr) += 1;
  333. (*src_ptr) += 1;
  334. break;
  335. case R_IMM8:
  336. if (reloc->howto->partial_inplace)
  337. val += bfd_get_8 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
  338. /* Fall through. */
  339. case R_BYTE0:
  340. bfd_put_8 (in_abfd, val, data + *dst_ptr);
  341. (*dst_ptr) += 1;
  342. (*src_ptr) += 1;
  343. break;
  344. case R_WORD1:
  345. bfd_put_16 (in_abfd, val >> 16, data + *dst_ptr);
  346. (*dst_ptr) += 2;
  347. (*src_ptr) += 2;
  348. break;
  349. case R_IMM16:
  350. if (reloc->howto->partial_inplace)
  351. val += bfd_get_16 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
  352. /* Fall through. */
  353. case R_WORD0:
  354. bfd_put_16 (in_abfd, val, data + *dst_ptr);
  355. (*dst_ptr) += 2;
  356. (*src_ptr) += 2;
  357. break;
  358. case R_IMM24:
  359. if (reloc->howto->partial_inplace)
  360. val += (bfd_get_16 ( in_abfd, data+*src_ptr)
  361. + (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16))
  362. & reloc->howto->src_mask;
  363. bfd_put_16 (in_abfd, val, data + *dst_ptr);
  364. bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2);
  365. (*dst_ptr) += 3;
  366. (*src_ptr) += 3;
  367. break;
  368. case R_IMM32:
  369. if (reloc->howto->partial_inplace)
  370. val += bfd_get_32 ( in_abfd, data+*src_ptr) & reloc->howto->src_mask;
  371. bfd_put_32 (in_abfd, val, data + *dst_ptr);
  372. (*dst_ptr) += 4;
  373. (*src_ptr) += 4;
  374. break;
  375. case R_JR:
  376. {
  377. if (reloc->howto->partial_inplace)
  378. val += (signed char)(bfd_get_8 ( in_abfd, data+*src_ptr)
  379. & reloc->howto->src_mask);
  380. bfd_vma dot = (*dst_ptr
  381. + input_section->output_offset
  382. + input_section->output_section->vma);
  383. int gap = val - dot;
  384. if (gap >= 128 || gap < -128)
  385. (*link_info->callbacks->reloc_overflow)
  386. (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr),
  387. reloc->howto->name, reloc->addend, input_section->owner,
  388. input_section, reloc->address);
  389. bfd_put_8 (in_abfd, gap, data + *dst_ptr);
  390. (*dst_ptr)++;
  391. (*src_ptr)++;
  392. break;
  393. }
  394. case R_IMM16BE:
  395. if (reloc->howto->partial_inplace)
  396. val += (bfd_get_8 ( in_abfd, data+*src_ptr+0) * 0x100 +
  397. bfd_get_8 ( in_abfd, data+*src_ptr+1)) & reloc->howto->src_mask;
  398. bfd_put_8 (in_abfd, val >> 8, data + *dst_ptr+0);
  399. bfd_put_8 (in_abfd, val, data + *dst_ptr+1);
  400. (*dst_ptr) += 2;
  401. (*src_ptr) += 2;
  402. break;
  403. default:
  404. abort ();
  405. }
  406. }
  407. static bool
  408. z80_is_local_label_name (bfd * abfd ATTRIBUTE_UNUSED,
  409. const char * name)
  410. {
  411. return (name[0] == '.' && name[1] == 'L') ||
  412. _bfd_coff_is_local_label_name (abfd, name);
  413. }
  414. #define coff_bfd_is_local_label_name z80_is_local_label_name
  415. #define coff_reloc16_extra_cases extra_case
  416. #define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup
  417. #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
  418. #ifndef bfd_pe_print_pdata
  419. #define bfd_pe_print_pdata NULL
  420. #endif
  421. #include "coffcode.h"
  422. #undef coff_bfd_get_relocated_section_contents
  423. #define coff_bfd_get_relocated_section_contents \
  424. bfd_coff_reloc16_get_relocated_section_contents
  425. #undef coff_bfd_relax_section
  426. #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
  427. CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
  428. SEC_CODE | SEC_DATA, '\0', NULL,
  429. COFF_SWAP_TABLE)