coff-z80.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* BFD back-end for Zilog Z80 COFF binaries.
  2. Copyright (C) 2005-2015 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. #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER 0
  25. static reloc_howto_type r_imm32 =
  26. HOWTO (R_IMM32, 0, 2, 32, FALSE, 0,
  27. complain_overflow_dont, 0, "r_imm32", TRUE, 0xffffffff, 0xffffffff,
  28. FALSE);
  29. static reloc_howto_type r_imm24 =
  30. HOWTO (R_IMM24, 0, 1, 24, FALSE, 0,
  31. complain_overflow_dont, 0, "r_imm24", TRUE, 0x00ffffff, 0x00ffffff,
  32. FALSE);
  33. static reloc_howto_type r_imm16 =
  34. HOWTO (R_IMM16, 0, 1, 16, FALSE, 0,
  35. complain_overflow_dont, 0, "r_imm16", TRUE, 0x0000ffff, 0x0000ffff,
  36. FALSE);
  37. static reloc_howto_type r_imm8 =
  38. HOWTO (R_IMM8, 0, 0, 8, FALSE, 0,
  39. complain_overflow_bitfield, 0, "r_imm8", TRUE, 0x000000ff, 0x000000ff,
  40. FALSE);
  41. static reloc_howto_type r_jr =
  42. HOWTO (R_JR, 0, 0, 8, TRUE, 0,
  43. complain_overflow_signed, 0, "r_jr", FALSE, 0, 0xFF,
  44. FALSE);
  45. static reloc_howto_type r_off8 =
  46. HOWTO (R_OFF8, 0, 0, 8, FALSE, 0,
  47. complain_overflow_signed, 0,"r_off8", FALSE, 0, 0xff,
  48. FALSE);
  49. #define BADMAG(x) Z80BADMAG(x)
  50. #define Z80 1 /* Customize coffcode.h. */
  51. #define __A_MAGIC_SET__
  52. /* Code to swap in the reloc. */
  53. #define SWAP_IN_RELOC_OFFSET H_GET_32
  54. #define SWAP_OUT_RELOC_OFFSET H_PUT_32
  55. #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \
  56. dst->r_stuff[0] = 'S'; \
  57. dst->r_stuff[1] = 'C';
  58. /* Code to turn a r_type into a howto ptr, uses the above howto table. */
  59. static void
  60. rtype2howto (arelent *internal, struct internal_reloc *dst)
  61. {
  62. switch (dst->r_type)
  63. {
  64. default:
  65. internal->howto = NULL;
  66. break;
  67. case R_IMM8:
  68. internal->howto = &r_imm8;
  69. break;
  70. case R_IMM16:
  71. internal->howto = &r_imm16;
  72. break;
  73. case R_IMM24:
  74. internal->howto = &r_imm24;
  75. break;
  76. case R_IMM32:
  77. internal->howto = &r_imm32;
  78. break;
  79. case R_JR:
  80. internal->howto = &r_jr;
  81. break;
  82. case R_OFF8:
  83. internal->howto = &r_off8;
  84. break;
  85. }
  86. }
  87. #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry)
  88. static reloc_howto_type *
  89. coff_z80_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  90. bfd_reloc_code_real_type code)
  91. {
  92. switch (code)
  93. {
  94. case BFD_RELOC_8: return & r_imm8;
  95. case BFD_RELOC_16: return & r_imm16;
  96. case BFD_RELOC_24: return & r_imm24;
  97. case BFD_RELOC_32: return & r_imm32;
  98. case BFD_RELOC_8_PCREL: return & r_jr;
  99. case BFD_RELOC_Z80_DISP8: return & r_off8;
  100. default: BFD_FAIL ();
  101. return NULL;
  102. }
  103. }
  104. static reloc_howto_type *
  105. coff_z80_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
  106. const char *r_name)
  107. {
  108. if (strcasecmp (r_imm8.name, r_name) == 0)
  109. return &r_imm8;
  110. if (strcasecmp (r_imm16.name, r_name) == 0)
  111. return &r_imm16;
  112. if (strcasecmp (r_imm24.name, r_name) == 0)
  113. return &r_imm24;
  114. if (strcasecmp (r_imm32.name, r_name) == 0)
  115. return &r_imm32;
  116. if (strcasecmp (r_jr.name, r_name) == 0)
  117. return &r_jr;
  118. if (strcasecmp (r_off8.name, r_name) == 0)
  119. return &r_off8;
  120. return NULL;
  121. }
  122. /* Perform any necessary magic to the addend in a reloc entry. */
  123. #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
  124. cache_ptr->addend = ext_reloc.r_offset;
  125. #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \
  126. reloc_processing(relent, reloc, symbols, abfd, section)
  127. static void
  128. reloc_processing (arelent *relent,
  129. struct internal_reloc *reloc,
  130. asymbol **symbols,
  131. bfd *abfd,
  132. asection *section)
  133. {
  134. relent->address = reloc->r_vaddr;
  135. rtype2howto (relent, reloc);
  136. if (reloc->r_symndx > 0)
  137. relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
  138. else
  139. relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
  140. relent->addend = reloc->r_offset;
  141. relent->address -= section->vma;
  142. }
  143. static void
  144. extra_case (bfd *in_abfd,
  145. struct bfd_link_info *link_info,
  146. struct bfd_link_order *link_order,
  147. arelent *reloc,
  148. bfd_byte *data,
  149. unsigned int *src_ptr,
  150. unsigned int *dst_ptr)
  151. {
  152. asection * input_section = link_order->u.indirect.section;
  153. int val;
  154. switch (reloc->howto->type)
  155. {
  156. case R_OFF8:
  157. val = bfd_coff_reloc16_get_value (reloc, link_info,
  158. input_section);
  159. if (val>127 || val<-128) /* Test for overflow. */
  160. {
  161. if (! ((*link_info->callbacks->reloc_overflow)
  162. (link_info, NULL,
  163. bfd_asymbol_name (*reloc->sym_ptr_ptr),
  164. reloc->howto->name, reloc->addend, input_section->owner,
  165. input_section, reloc->address)))
  166. abort ();
  167. }
  168. bfd_put_8 (in_abfd, val, data + *dst_ptr);
  169. (*dst_ptr) += 1;
  170. (*src_ptr) += 1;
  171. break;
  172. case R_IMM8:
  173. val = bfd_get_8 ( in_abfd, data+*src_ptr)
  174. + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
  175. bfd_put_8 (in_abfd, val, data + *dst_ptr);
  176. (*dst_ptr) += 1;
  177. (*src_ptr) += 1;
  178. break;
  179. case R_IMM16:
  180. val = bfd_get_16 ( in_abfd, data+*src_ptr)
  181. + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
  182. bfd_put_16 (in_abfd, val, data + *dst_ptr);
  183. (*dst_ptr) += 2;
  184. (*src_ptr) += 2;
  185. break;
  186. case R_IMM24:
  187. val = bfd_get_16 ( in_abfd, data+*src_ptr)
  188. + (bfd_get_8 ( in_abfd, data+*src_ptr+2) << 16)
  189. + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
  190. bfd_put_16 (in_abfd, val, data + *dst_ptr);
  191. bfd_put_8 (in_abfd, val >> 16, data + *dst_ptr+2);
  192. (*dst_ptr) += 3;
  193. (*src_ptr) += 3;
  194. break;
  195. case R_IMM32:
  196. val = bfd_get_32 ( in_abfd, data+*src_ptr)
  197. + bfd_coff_reloc16_get_value (reloc, link_info, input_section);
  198. bfd_put_32 (in_abfd, val, data + *dst_ptr);
  199. (*dst_ptr) += 4;
  200. (*src_ptr) += 4;
  201. break;
  202. case R_JR:
  203. {
  204. bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info,
  205. input_section);
  206. bfd_vma dot = (*dst_ptr
  207. + input_section->output_offset
  208. + input_section->output_section->vma);
  209. int gap = dst - dot - 1; /* -1, Since the offset is relative
  210. to the value of PC after reading
  211. the offset. */
  212. if (gap >= 128 || gap < -128)
  213. {
  214. if (! ((*link_info->callbacks->reloc_overflow)
  215. (link_info, NULL,
  216. bfd_asymbol_name (*reloc->sym_ptr_ptr),
  217. reloc->howto->name, reloc->addend, input_section->owner,
  218. input_section, reloc->address)))
  219. abort ();
  220. }
  221. bfd_put_8 (in_abfd, gap, data + *dst_ptr);
  222. (*dst_ptr)++;
  223. (*src_ptr)++;
  224. break;
  225. }
  226. default:
  227. abort ();
  228. }
  229. }
  230. #define coff_reloc16_extra_cases extra_case
  231. #define coff_bfd_reloc_type_lookup coff_z80_reloc_type_lookup
  232. #define coff_bfd_reloc_name_lookup coff_z80_reloc_name_lookup
  233. #ifndef bfd_pe_print_pdata
  234. #define bfd_pe_print_pdata NULL
  235. #endif
  236. #include "coffcode.h"
  237. #undef coff_bfd_get_relocated_section_contents
  238. #define coff_bfd_get_relocated_section_contents \
  239. bfd_coff_reloc16_get_relocated_section_contents
  240. #undef coff_bfd_relax_section
  241. #define coff_bfd_relax_section bfd_coff_reloc16_relax_section
  242. CREATE_LITTLE_COFF_TARGET_VEC (z80_coff_vec, "coff-z80", 0,
  243. SEC_CODE | SEC_DATA, '\0', NULL,
  244. COFF_SWAP_TABLE)