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