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