1 /* BFD back-end for WDC 65816 COFF binaries. 2 Copyright (C) 1995-2016 Free Software Foundation, Inc. 3 Written by Steve Chamberlain, <sac (at) cygnus.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/w65.h" 27 #include "coff/internal.h" 28 #include "libcoff.h" 29 30 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (1) 31 static reloc_howto_type howto_table[] = 32 { 33 HOWTO (R_W65_ABS8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), 34 HOWTO (R_W65_ABS16, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), 35 HOWTO (R_W65_ABS24, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "abs24", TRUE, 0x00ffffff, 0x00ffffff, FALSE), 36 HOWTO (R_W65_ABS8S8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, ">abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), 37 HOWTO (R_W65_ABS8S16, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "^abs8", TRUE, 0x000000ff, 0x000000ff, FALSE), 38 HOWTO (R_W65_ABS16S8, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, ">abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), 39 HOWTO (R_W65_ABS16S16,1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "^abs16", TRUE, 0x0000ffff, 0x0000ffff, FALSE), 40 HOWTO (R_W65_PCR8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "pcrel8", TRUE, 0x000000ff, 0x000000ff, TRUE), 41 HOWTO (R_W65_PCR16, 1, 0, 16, FALSE, 0, complain_overflow_bitfield, 0, "pcrel16", TRUE, 0x0000ffff, 0x0000ffff, TRUE), 42 HOWTO (R_W65_DP, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 0, "dp", TRUE, 0x000000ff, 0x000000ff, FALSE), 43 }; 44 45 #define NUM_HOWTOS (sizeof (howto_table) / sizeof (howto_table[0])) 46 47 /* Turn a howto into a reloc number. */ 48 49 #define SELECT_RELOC(x,howto) \ 50 { x.r_type = select_reloc(howto); } 51 52 #define BADMAG(x) (W65BADMAG(x)) 53 #define W65 1 /* Customize coffcode.h */ 54 #define __A_MAGIC_SET__ 55 56 /* Code to swap in the reloc */ 57 #define SWAP_IN_RELOC_OFFSET H_GET_32 58 #define SWAP_OUT_RELOC_OFFSET H_PUT_32 59 #define SWAP_OUT_RELOC_EXTRA(abfd, src, dst) \ 60 dst->r_stuff[0] = 'S'; \ 61 dst->r_stuff[1] = 'C'; 62 63 static int 64 select_reloc (reloc_howto_type *howto) 65 { 66 return howto->type; 67 } 68 69 /* Code to turn a r_type into a howto ptr, uses the above howto table. */ 70 71 static void 72 rtype2howto (arelent *internal, 73 struct internal_reloc *dst) 74 { 75 if (dst->r_type > 0 && dst->r_type <= NUM_HOWTOS) 76 internal->howto = howto_table + dst->r_type - 1; 77 else 78 internal->howto = NULL; 79 } 80 81 #define RTYPE2HOWTO(internal, relocentry) rtype2howto(internal,relocentry) 82 83 /* Perform any necessary magic to the addend in a reloc entry. */ 84 85 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \ 86 cache_ptr->addend = ext_reloc.r_offset; 87 88 #define RELOC_PROCESSING(relent,reloc,symbols,abfd,section) \ 89 reloc_processing(relent, reloc, symbols, abfd, section) 90 91 static void 92 reloc_processing (arelent * relent, 93 struct internal_reloc *reloc, 94 asymbol ** symbols, 95 bfd * abfd, 96 asection * section) 97 { 98 relent->address = reloc->r_vaddr; 99 rtype2howto (relent, reloc); 100 101 if (((int) reloc->r_symndx) > 0) 102 relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx]; 103 else 104 relent->sym_ptr_ptr = (asymbol **) bfd_abs_section_ptr->symbol_ptr_ptr; 105 106 relent->addend = reloc->r_offset; 107 108 relent->address -= section->vma; 109 /* relent->section = 0;*/ 110 } 111 112 static int 113 w65_reloc16_estimate (bfd *abfd, 114 asection *input_section, 115 arelent *reloc, 116 unsigned int shrink, 117 struct bfd_link_info *link_info) 118 { 119 bfd_vma value; 120 bfd_vma dot; 121 bfd_vma gap; 122 123 /* The address of the thing to be relocated will have moved back by 124 the size of the shrink - but we don't change reloc->address here, 125 since we need it to know where the relocation lives in the source 126 uncooked section. */ 127 128 /* reloc->address -= shrink; conceptual */ 129 130 bfd_vma address = reloc->address - shrink; 131 132 switch (reloc->howto->type) 133 { 134 case R_MOV16B2: 135 case R_JMP2: 136 shrink+=2; 137 break; 138 139 /* Thing is a move one byte. */ 140 case R_MOV16B1: 141 value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); 142 143 if (value >= 0xff00) 144 { 145 /* Change the reloc type from 16bit, possible 8 to 8bit 146 possible 16. */ 147 reloc->howto = reloc->howto + 1; 148 /* The place to relc moves back by one. */ 149 /* This will be two bytes smaller in the long run. */ 150 shrink += 2; 151 bfd_perform_slip (abfd, 2, input_section, address); 152 } 153 154 break; 155 /* This is the 24 bit branch which could become an 8 bitter, 156 the relocation points to the first byte of the insn, not the 157 actual data. */ 158 159 case R_JMPL1: 160 value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); 161 162 dot = input_section->output_section->vma + 163 input_section->output_offset + address; 164 165 /* See if the address we're looking at within 127 bytes of where 166 we are, if so then we can use a small branch rather than the 167 jump we were going to. */ 168 gap = value - dot; 169 170 if (-120 < (long) gap && (long) gap < 120) 171 { 172 /* Change the reloc type from 24bit, possible 8 to 8bit 173 possible 32. */ 174 reloc->howto = reloc->howto + 1; 175 /* This will be two bytes smaller in the long run. */ 176 shrink += 2; 177 bfd_perform_slip (abfd, 2, input_section, address); 178 } 179 break; 180 181 case R_JMP1: 182 value = bfd_coff_reloc16_get_value (reloc, link_info, input_section); 183 184 dot = input_section->output_section->vma + 185 input_section->output_offset + address; 186 187 /* See if the address we're looking at within 127 bytes of where 188 we are, if so then we can use a small branch rather than the 189 jump we were going to. */ 190 gap = value - (dot - shrink); 191 192 if (-120 < (long) gap && (long) gap < 120) 193 { 194 /* Change the reloc type from 16bit, possible 8 to 8bit 195 possible 16. */ 196 reloc->howto = reloc->howto + 1; 197 /* The place to relc moves back by one. */ 198 199 /* This will be two bytes smaller in the long run. */ 200 shrink += 2; 201 bfd_perform_slip (abfd, 2, input_section, address); 202 } 203 break; 204 } 205 206 return shrink; 207 } 208 209 /* First phase of a relaxing link. */ 210 211 /* Reloc types 212 large small 213 R_MOV16B1 R_MOV16B2 mov.b with 16bit or 8 bit address 214 R_JMP1 R_JMP2 jmp or pcrel branch 215 R_JMPL1 R_JMPL_B8 24jmp or pcrel branch 216 R_MOV24B1 R_MOV24B2 24 or 8 bit reloc for mov.b */ 217 218 static void 219 w65_reloc16_extra_cases (bfd *abfd, 220 struct bfd_link_info *link_info, 221 struct bfd_link_order *link_order, 222 arelent *reloc, 223 bfd_byte *data, 224 unsigned int *src_ptr, 225 unsigned int *dst_ptr) 226 { 227 unsigned int src_address = *src_ptr; 228 unsigned int dst_address = *dst_ptr; 229 asection *input_section = link_order->u.indirect.section; 230 231 switch (reloc->howto->type) 232 { 233 case R_W65_ABS8: 234 case R_W65_DP: 235 { 236 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 237 input_section); 238 bfd_put_8 (abfd, gap, data + dst_address); 239 dst_address += 1; 240 src_address += 1; 241 } 242 break; 243 244 case R_W65_ABS8S8: 245 { 246 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 247 input_section); 248 gap >>= 8; 249 bfd_put_8 (abfd, gap, data + dst_address); 250 dst_address += 1; 251 src_address += 1; 252 } 253 break; 254 255 case R_W65_ABS8S16: 256 { 257 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 258 input_section); 259 gap >>= 16; 260 bfd_put_8 (abfd, gap, data + dst_address); 261 dst_address += 1; 262 src_address += 1; 263 } 264 break; 265 266 case R_W65_ABS16: 267 { 268 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 269 input_section); 270 271 bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); 272 dst_address += 2; 273 src_address += 2; 274 } 275 break; 276 case R_W65_ABS16S8: 277 { 278 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 279 input_section); 280 gap >>= 8; 281 bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); 282 dst_address += 2; 283 src_address += 2; 284 } 285 break; 286 case R_W65_ABS16S16: 287 { 288 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 289 input_section); 290 gap >>= 16; 291 bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); 292 dst_address += 2; 293 src_address += 2; 294 } 295 break; 296 297 case R_W65_ABS24: 298 { 299 unsigned int gap = bfd_coff_reloc16_get_value (reloc, link_info, 300 input_section); 301 bfd_put_16 (abfd, (bfd_vma) gap, data + dst_address); 302 bfd_put_8 (abfd, gap >> 16, data+dst_address + 2); 303 dst_address += 3; 304 src_address += 3; 305 } 306 break; 307 308 case R_W65_PCR8: 309 { 310 int gap = bfd_coff_reloc16_get_value (reloc, link_info, 311 input_section); 312 bfd_vma dot = (dst_address 313 + input_section->output_offset 314 + input_section->output_section->vma); 315 316 gap -= dot + 1; 317 if (gap < -128 || gap > 127) 318 (*link_info->callbacks->reloc_overflow) 319 (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 320 reloc->howto->name, reloc->addend, input_section->owner, 321 input_section, reloc->address); 322 323 bfd_put_8 (abfd, gap, data + dst_address); 324 dst_address += 1; 325 src_address += 1; 326 } 327 break; 328 329 case R_W65_PCR16: 330 { 331 bfd_vma gap = bfd_coff_reloc16_get_value (reloc, link_info, 332 input_section); 333 bfd_vma dot = (dst_address 334 + input_section->output_offset 335 + input_section->output_section->vma); 336 337 /* This wraps within the page, so ignore the relativeness, look at the 338 high part. */ 339 if ((gap & 0xf0000) != (dot & 0xf0000)) 340 (*link_info->callbacks->reloc_overflow) 341 (link_info, NULL, bfd_asymbol_name (*reloc->sym_ptr_ptr), 342 reloc->howto->name, reloc->addend, input_section->owner, 343 input_section, reloc->address); 344 345 gap -= dot + 2; 346 bfd_put_16 (abfd, gap, data + dst_address); 347 dst_address += 2; 348 src_address += 2; 349 } 350 break; 351 default: 352 printf (_("ignoring reloc %s\n"), reloc->howto->name); 353 break; 354 355 } 356 *src_ptr = src_address; 357 *dst_ptr = dst_address; 358 } 359 360 #define coff_reloc16_extra_cases w65_reloc16_extra_cases 361 #define coff_reloc16_estimate w65_reloc16_estimate 362 363 #ifndef bfd_pe_print_pdata 364 #define bfd_pe_print_pdata NULL 365 #endif 366 367 #include "coffcode.h" 368 369 #undef coff_bfd_get_relocated_section_contents 370 #undef coff_bfd_relax_section 371 #define coff_bfd_get_relocated_section_contents \ 372 bfd_coff_reloc16_get_relocated_section_contents 373 #define coff_bfd_relax_section bfd_coff_reloc16_relax_section 374 375 CREATE_LITTLE_COFF_TARGET_VEC (w65_coff_vec, "coff-w65", BFD_IS_RELAXABLE, 0, '_', NULL, COFF_SWAP_TABLE) 376