1 1.1 christos /* BFD back-end for Zilog Z800n COFF binaries. 2 1.10 christos Copyright (C) 1992-2025 Free Software Foundation, Inc. 3 1.1 christos Contributed by Cygnus Support. 4 1.1 christos Written by Steve Chamberlain, <sac (at) cygnus.com>. 5 1.1 christos 6 1.1 christos This file is part of BFD, the Binary File Descriptor library. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3 of the License, or 11 1.1 christos (at your option) any later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 christos GNU General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program; if not, write to the Free Software 20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 1.1 christos MA 02110-1301, USA. */ 22 1.1 christos 23 1.1 christos #include "sysdep.h" 24 1.1 christos #include "bfd.h" 25 1.1 christos #include "libbfd.h" 26 1.1 christos #include "bfdlink.h" 27 1.1 christos #include "coff/z8k.h" 28 1.1 christos #include "coff/internal.h" 29 1.1 christos #include "libcoff.h" 30 1.1 christos 31 1.1 christos #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) 32 1.1 christos 33 1.1 christos static reloc_howto_type r_imm32 = 34 1.8 christos HOWTO (R_IMM32, 0, 4, 32, false, 0, 35 1.8 christos complain_overflow_bitfield, 0, "r_imm32", true, 0xffffffff, 36 1.8 christos 0xffffffff, false); 37 1.1 christos 38 1.1 christos static reloc_howto_type r_imm4l = 39 1.8 christos HOWTO (R_IMM4L, 0, 1, 4, false, 0, 40 1.8 christos complain_overflow_bitfield, 0, "r_imm4l", true, 0xf, 0xf, false); 41 1.1 christos 42 1.1 christos static reloc_howto_type r_da = 43 1.8 christos HOWTO (R_IMM16, 0, 2, 16, false, 0, 44 1.8 christos complain_overflow_bitfield, 0, "r_da", true, 0x0000ffff, 0x0000ffff, 45 1.8 christos false); 46 1.1 christos 47 1.1 christos static reloc_howto_type r_imm8 = 48 1.8 christos HOWTO (R_IMM8, 0, 1, 8, false, 0, 49 1.8 christos complain_overflow_bitfield, 0, "r_imm8", true, 0x000000ff, 0x000000ff, 50 1.8 christos false); 51 1.1 christos 52 1.1 christos static reloc_howto_type r_rel16 = 53 1.8 christos HOWTO (R_REL16, 0, 2, 16, false, 0, 54 1.8 christos complain_overflow_bitfield, 0, "r_rel16", true, 0x0000ffff, 0x0000ffff, 55 1.8 christos true); 56 1.1 christos 57 1.1 christos static reloc_howto_type r_jr = 58 1.8 christos HOWTO (R_JR, 1, 1, 8, true, 0, complain_overflow_signed, 0, 59 1.8 christos "r_jr", true, 0xff, 0xff, true); 60 1.1 christos 61 1.1 christos static reloc_howto_type r_disp7 = 62 1.8 christos HOWTO (R_DISP7, 0, 1, 7, true, 0, complain_overflow_bitfield, 0, 63 1.8 christos "r_disp7", true, 0x7f, 0x7f, true); 64 1.1 christos 65 1.1 christos static reloc_howto_type r_callr = 66 1.8 christos HOWTO (R_CALLR, 1, 2, 12, true, 0, complain_overflow_signed, 0, 67 1.8 christos "r_callr", true, 0xfff, 0xfff, true); 68 1.1 christos 69 1.1 christos #define BADMAG(x) Z8KBADMAG(x) 70 1.1 christos #define Z8K 1 /* Customize coffcode.h. */ 71 1.1 christos #define __A_MAGIC_SET__ 72 1.1 christos 73 1.1 christos /* Code to swap in the reloc. */ 74 1.1 christos #define SWAP_IN_RELOC_OFFSET H_GET_32 75 1.1 christos #define SWAP_OUT_RELOC_OFFSET H_PUT_32 76 1.1 christos #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ 77 1.1 christos dst->r_stuff[0] = 'S'; \ 78 1.1 christos dst->r_stuff[1] = 'C'; 79 1.1 christos 80 1.1 christos /* Code to turn a r_type into a howto ptr, uses the above howto table. */ 81 1.1 christos 82 1.1 christos static void 83 1.1 christos rtype2howto (arelent *internal, struct internal_reloc *dst) 84 1.1 christos { 85 1.1 christos switch (dst->r_type) 86 1.1 christos { 87 1.1 christos default: 88 1.3 christos internal->howto = NULL; 89 1.1 christos break; 90 1.1 christos case R_IMM8: 91 1.1 christos internal->howto = &r_imm8; 92 1.1 christos break; 93 1.1 christos case R_IMM16: 94 1.1 christos internal->howto = &r_da; 95 1.1 christos break; 96 1.1 christos case R_JR: 97 1.1 christos internal->howto = &r_jr; 98 1.1 christos break; 99 1.1 christos case R_DISP7: 100 1.1 christos internal->howto = &r_disp7; 101 1.1 christos break; 102 1.1 christos case R_CALLR: 103 1.1 christos internal->howto = &r_callr; 104 1.1 christos break; 105 1.1 christos case R_REL16: 106 1.1 christos internal->howto = &r_rel16; 107 1.1 christos break; 108 1.1 christos case R_IMM32: 109 1.1 christos internal->howto = &r_imm32; 110 1.1 christos break; 111 1.1 christos case R_IMM4L: 112 1.1 christos internal->howto = &r_imm4l; 113 1.1 christos break; 114 1.1 christos } 115 1.1 christos } 116 1.1 christos 117 1.1 christos #define RTYPE2HOWTO(internal, relocentry) rtype2howto (internal, relocentry) 118 1.1 christos 119 1.1 christos static reloc_howto_type * 120 1.1 christos coff_z8k_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 121 1.6 christos bfd_reloc_code_real_type code) 122 1.1 christos { 123 1.1 christos switch (code) 124 1.1 christos { 125 1.6 christos case BFD_RELOC_8: return & r_imm8; 126 1.6 christos case BFD_RELOC_16: return & r_da; 127 1.6 christos case BFD_RELOC_32: return & r_imm32; 128 1.6 christos case BFD_RELOC_8_PCREL: return & r_jr; 129 1.6 christos case BFD_RELOC_16_PCREL: return & r_rel16; 130 1.6 christos case BFD_RELOC_Z8K_DISP7: return & r_disp7; 131 1.6 christos case BFD_RELOC_Z8K_CALLR: return & r_callr; 132 1.6 christos case BFD_RELOC_Z8K_IMM4L: return & r_imm4l; 133 1.1 christos default: BFD_FAIL (); 134 1.1 christos return 0; 135 1.1 christos } 136 1.1 christos } 137 1.1 christos 138 1.1 christos static reloc_howto_type * 139 1.1 christos coff_z8k_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 140 1.1 christos const char *r_name) 141 1.1 christos { 142 1.1 christos if (strcasecmp (r_imm8.name, r_name) == 0) 143 1.1 christos return &r_imm8; 144 1.1 christos if (strcasecmp (r_da.name, r_name) == 0) 145 1.1 christos return &r_da; 146 1.1 christos if (strcasecmp (r_imm32.name, r_name) == 0) 147 1.1 christos return &r_imm32; 148 1.1 christos if (strcasecmp (r_jr.name, r_name) == 0) 149 1.1 christos return &r_jr; 150 1.1 christos if (strcasecmp (r_rel16.name, r_name) == 0) 151 1.1 christos return &r_rel16; 152 1.1 christos if (strcasecmp (r_disp7.name, r_name) == 0) 153 1.1 christos return &r_disp7; 154 1.1 christos if (strcasecmp (r_callr.name, r_name) == 0) 155 1.1 christos return &r_callr; 156 1.1 christos if (strcasecmp (r_imm4l.name, r_name) == 0) 157 1.1 christos return &r_imm4l; 158 1.1 christos 159 1.1 christos return NULL; 160 1.1 christos } 161 1.1 christos 162 1.1 christos /* Perform any necessary magic to the addend in a reloc entry. */ 163 1.1 christos 164 1.1 christos #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ 165 1.1 christos cache_ptr->addend = ext_reloc.r_offset; 166 1.1 christos 167 1.1 christos #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ 168 1.1 christos reloc_processing(relent, reloc, symbols, abfd, section) 169 1.1 christos 170 1.1 christos static void 171 1.1 christos reloc_processing (arelent *relent, 172 1.6 christos struct internal_reloc *reloc, 173 1.6 christos asymbol **symbols, 174 1.6 christos bfd *abfd, 175 1.6 christos asection *section) 176 1.1 christos { 177 1.1 christos relent->address = reloc->r_vaddr; 178 1.1 christos rtype2howto (relent, reloc); 179 1.1 christos 180 1.9 christos if (reloc->r_symndx == -1 || symbols == NULL) 181 1.10 christos relent->sym_ptr_ptr = &bfd_abs_section_ptr->symbol; 182 1.8 christos else if (reloc->r_symndx >= 0 && reloc->r_symndx < obj_conv_table_size (abfd)) 183 1.1 christos relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; 184 1.1 christos else 185 1.8 christos { 186 1.8 christos _bfd_error_handler 187 1.8 christos /* xgettext:c-format */ 188 1.8 christos (_("%pB: warning: illegal symbol index %ld in relocs"), 189 1.8 christos abfd, reloc->r_symndx); 190 1.10 christos relent->sym_ptr_ptr = &bfd_abs_section_ptr->symbol; 191 1.8 christos } 192 1.1 christos relent->addend = reloc->r_offset; 193 1.1 christos relent->address -= section->vma; 194 1.1 christos } 195 1.1 christos 196 1.9 christos static bool 197 1.1 christos extra_case (bfd *in_abfd, 198 1.6 christos struct bfd_link_info *link_info, 199 1.6 christos struct bfd_link_order *link_order, 200 1.6 christos arelent *reloc, 201 1.6 christos bfd_byte *data, 202 1.9 christos size_t *src_ptr, 203 1.9 christos size_t *dst_ptr) 204 1.1 christos { 205 1.1 christos asection * input_section = link_order->u.indirect.section; 206 1.9 christos bfd_size_type end = bfd_get_section_limit_octets (in_abfd, input_section); 207 1.9 christos bfd_size_type reloc_size = bfd_get_reloc_size (reloc->howto); 208 1.9 christos 209 1.9 christos if (*src_ptr > end 210 1.9 christos || reloc_size > end - *src_ptr) 211 1.9 christos { 212 1.9 christos link_info->callbacks->einfo 213 1.9 christos /* xgettext:c-format */ 214 1.9 christos (_("%X%P: %pB(%pA): relocation \"%pR\" goes out of range\n"), 215 1.9 christos in_abfd, input_section, reloc); 216 1.9 christos return false; 217 1.9 christos } 218 1.1 christos 219 1.1 christos switch (reloc->howto->type) 220 1.1 christos { 221 1.1 christos case R_IMM8: 222 1.1 christos bfd_put_8 (in_abfd, 223 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info, input_section), 224 1.1 christos data + *dst_ptr); 225 1.9 christos *dst_ptr += 1; 226 1.9 christos *src_ptr += 1; 227 1.1 christos break; 228 1.1 christos 229 1.1 christos case R_IMM32: 230 1.1 christos /* If no flags are set, assume immediate value. */ 231 1.1 christos if (! (*reloc->sym_ptr_ptr)->section->flags) 232 1.1 christos { 233 1.1 christos bfd_put_32 (in_abfd, 234 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info, 235 1.1 christos input_section), 236 1.1 christos data + *dst_ptr); 237 1.1 christos } 238 1.1 christos else 239 1.1 christos { 240 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, 241 1.1 christos input_section); 242 1.1 christos /* Addresses are 23 bit, and the layout of those in a 32-bit 243 1.1 christos value is as follows: 244 1.1 christos 1AAAAAAA xxxxxxxx AAAAAAAA AAAAAAAA 245 1.1 christos (A - address bits, x - ignore). */ 246 1.1 christos dst = (dst & 0xffff) | ((dst & 0xff0000) << 8) | 0x80000000; 247 1.1 christos bfd_put_32 (in_abfd, dst, data + *dst_ptr); 248 1.1 christos } 249 1.9 christos *dst_ptr += 4; 250 1.9 christos *src_ptr += 4; 251 1.1 christos break; 252 1.1 christos 253 1.1 christos case R_IMM4L: 254 1.1 christos bfd_put_8 (in_abfd, 255 1.1 christos ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0xf0) 256 1.9 christos | (0x0f & bfd_coff_reloc16_get_value (reloc, link_info, 257 1.9 christos input_section))), 258 1.1 christos data + *dst_ptr); 259 1.9 christos *dst_ptr += 1; 260 1.9 christos *src_ptr += 1; 261 1.1 christos break; 262 1.1 christos 263 1.1 christos case R_IMM16: 264 1.1 christos bfd_put_16 (in_abfd, 265 1.1 christos bfd_coff_reloc16_get_value (reloc, link_info, input_section), 266 1.1 christos data + *dst_ptr); 267 1.9 christos *dst_ptr += 2; 268 1.9 christos *src_ptr += 2; 269 1.1 christos break; 270 1.1 christos 271 1.1 christos case R_JR: 272 1.1 christos { 273 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, 274 1.1 christos input_section); 275 1.1 christos bfd_vma dot = (*dst_ptr 276 1.1 christos + input_section->output_offset 277 1.1 christos + input_section->output_section->vma); 278 1.9 christos /* -1, since we're in the odd byte of the word and the pc has 279 1.9 christos been incremented. */ 280 1.9 christos bfd_signed_vma gap = dst - dot - 1; 281 1.9 christos 282 1.9 christos if ((gap & 1) != 0 || gap > 254 || gap < -256) 283 1.9 christos { 284 1.9 christos link_info->callbacks->reloc_overflow 285 1.9 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 286 1.9 christos reloc->howto->name, reloc->addend, input_section->owner, 287 1.9 christos input_section, reloc->address); 288 1.9 christos return false; 289 1.9 christos } 290 1.9 christos 291 1.9 christos bfd_put_8 (in_abfd, gap / 2, data + *dst_ptr); 292 1.9 christos *dst_ptr += 1; 293 1.9 christos *src_ptr += 1; 294 1.1 christos break; 295 1.1 christos } 296 1.1 christos 297 1.1 christos case R_DISP7: 298 1.1 christos { 299 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, 300 1.1 christos input_section); 301 1.1 christos bfd_vma dot = (*dst_ptr 302 1.1 christos + input_section->output_offset 303 1.1 christos + input_section->output_section->vma); 304 1.9 christos bfd_signed_vma gap = dst - dot - 1; 305 1.1 christos 306 1.9 christos if ((gap & 1) != 0 || gap > 0 || gap < -254) 307 1.9 christos { 308 1.9 christos link_info->callbacks->reloc_overflow 309 1.9 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 310 1.9 christos reloc->howto->name, reloc->addend, input_section->owner, 311 1.9 christos input_section, reloc->address); 312 1.9 christos return false; 313 1.9 christos } 314 1.5 christos 315 1.1 christos bfd_put_8 (in_abfd, 316 1.9 christos ((bfd_get_8 (in_abfd, data + *dst_ptr) & 0x80) 317 1.9 christos + (-gap / 2 & 0x7f)), 318 1.6 christos data + *dst_ptr); 319 1.9 christos *dst_ptr += 1; 320 1.9 christos *src_ptr += 1; 321 1.1 christos break; 322 1.1 christos } 323 1.1 christos 324 1.1 christos case R_CALLR: 325 1.1 christos { 326 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, 327 1.1 christos input_section); 328 1.1 christos bfd_vma dot = (*dst_ptr 329 1.1 christos + input_section->output_offset 330 1.1 christos + input_section->output_section->vma); 331 1.9 christos bfd_signed_vma gap = dst - dot - 2; 332 1.1 christos 333 1.9 christos if ((gap & 1) != 0 || gap > 4096 || gap < -4095) 334 1.9 christos { 335 1.9 christos link_info->callbacks->reloc_overflow 336 1.9 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 337 1.9 christos reloc->howto->name, reloc->addend, input_section->owner, 338 1.9 christos input_section, reloc->address); 339 1.9 christos return false; 340 1.9 christos } 341 1.5 christos 342 1.1 christos bfd_put_16 (in_abfd, 343 1.9 christos ((bfd_get_16 (in_abfd, data + *dst_ptr) & 0xf000) 344 1.9 christos | (-gap / 2 & 0x0fff)), 345 1.6 christos data + *dst_ptr); 346 1.9 christos *dst_ptr += 2; 347 1.9 christos *src_ptr += 2; 348 1.1 christos break; 349 1.1 christos } 350 1.1 christos 351 1.1 christos case R_REL16: 352 1.1 christos { 353 1.1 christos bfd_vma dst = bfd_coff_reloc16_get_value (reloc, link_info, 354 1.1 christos input_section); 355 1.1 christos bfd_vma dot = (*dst_ptr 356 1.1 christos + input_section->output_offset 357 1.1 christos + input_section->output_section->vma); 358 1.9 christos bfd_signed_vma gap = dst - dot - 2; 359 1.1 christos 360 1.1 christos if (gap > 32767 || gap < -32768) 361 1.9 christos { 362 1.9 christos link_info->callbacks->reloc_overflow 363 1.9 christos (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 364 1.9 christos reloc->howto->name, reloc->addend, input_section->owner, 365 1.9 christos input_section, reloc->address); 366 1.9 christos return false; 367 1.9 christos } 368 1.9 christos 369 1.9 christos bfd_put_16 (in_abfd, gap, data + *dst_ptr); 370 1.9 christos *dst_ptr += 2; 371 1.9 christos *src_ptr += 2; 372 1.1 christos break; 373 1.1 christos } 374 1.1 christos 375 1.1 christos default: 376 1.9 christos link_info->callbacks->einfo 377 1.9 christos /* xgettext:c-format */ 378 1.9 christos (_("%X%P: %pB(%pA): relocation \"%pR\" is not supported\n"), 379 1.9 christos in_abfd, input_section, reloc); 380 1.9 christos return false; 381 1.1 christos } 382 1.9 christos return true; 383 1.1 christos } 384 1.1 christos 385 1.1 christos #define coff_reloc16_extra_cases extra_case 386 1.1 christos #define coff_bfd_reloc_type_lookup coff_z8k_reloc_type_lookup 387 1.1 christos #define coff_bfd_reloc_name_lookup coff_z8k_reloc_name_lookup 388 1.1 christos 389 1.1 christos #ifndef bfd_pe_print_pdata 390 1.1 christos #define bfd_pe_print_pdata NULL 391 1.1 christos #endif 392 1.1 christos 393 1.1 christos #include "coffcode.h" 394 1.1 christos 395 1.1 christos #undef coff_bfd_get_relocated_section_contents 396 1.1 christos #define coff_bfd_get_relocated_section_contents \ 397 1.1 christos bfd_coff_reloc16_get_relocated_section_contents 398 1.1 christos 399 1.1 christos #undef coff_bfd_relax_section 400 1.1 christos #define coff_bfd_relax_section bfd_coff_reloc16_relax_section 401 1.1 christos 402 1.3 christos CREATE_BIG_COFF_TARGET_VEC (z8k_coff_vec, "coff-z8k", 0, 0, '_', NULL, COFF_SWAP_TABLE) 403