1 /* Infineon XC16X-specific support for 16-bit ELF. 2 Copyright 2006 Free Software Foundation, Inc. 3 Contributed by KPIT Cummins Infosystems 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, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 20 21 #include "bfd.h" 22 #include "sysdep.h" 23 #include "libbfd.h" 24 #include "elf-bfd.h" 25 #include "elf/xc16x.h" 26 #include "elf/dwarf2.h" 27 #include "libiberty.h" 28 29 static reloc_howto_type xc16x_elf_howto_table [] = 30 { 31 /* This reloc does nothing. */ 32 HOWTO (R_XC16X_NONE, /* type */ 33 0, /* rightshift */ 34 1, /* size (0 = byte, 1 = short, 2 = long) */ 35 16, /* bitsize */ 36 FALSE, /* pc_relative */ 37 0, /* bitpos */ 38 complain_overflow_bitfield, /* complain_on_overflow */ 39 bfd_elf_generic_reloc, /* special_function */ 40 "R_XC16X_NONE", /* name */ 41 FALSE, /* partial_inplace */ 42 0, /* src_mask */ 43 0, /* dst_mask */ 44 FALSE), /* pcrel_offset */ 45 46 /* An 8 bit absolute relocation. */ 47 HOWTO (R_XC16X_ABS_8, /* type */ 48 0, /* rightshift */ 49 0, /* size (0 = byte, 1 = short, 2 = long) */ 50 8, /* bitsize */ 51 FALSE, /* pc_relative */ 52 8, /* bitpos */ 53 complain_overflow_bitfield, /* complain_on_overflow */ 54 bfd_elf_generic_reloc, /* special_function */ 55 "R_XC16X_ABS_8", /* name */ 56 TRUE, /* partial_inplace */ 57 0x0000, /* src_mask */ 58 0x00ff, /* dst_mask */ 59 FALSE), /* pcrel_offset */ 60 61 /* A 16 bit absolute relocation. */ 62 HOWTO (R_XC16X_ABS_16, /* type */ 63 0, /* rightshift */ 64 1, /* size (0 = byte, 1 = short, 2 = long) */ 65 16, /* bitsize */ 66 FALSE, /* pc_relative */ 67 0, /* bitpos */ 68 complain_overflow_dont, /* complain_on_overflow */ 69 bfd_elf_generic_reloc, /* special_function */ 70 "R_XC16X_ABS_16", /* name */ 71 TRUE, /* partial_inplace */ 72 0x00000000, /* src_mask */ 73 0x0000ffff, /* dst_mask */ 74 FALSE), /* pcrel_offset */ 75 76 HOWTO (R_XC16X_ABS_32, /* type */ 77 0, /* rightshift */ 78 2, /* size (0 = byte, 1 = short, 2 = long) */ 79 32, /* bitsize */ 80 FALSE, /* pc_relative */ 81 0, /* bitpos */ 82 complain_overflow_bitfield, /* complain_on_overflow */ 83 bfd_elf_generic_reloc, /* special_function */ 84 "R_XC16X_ABS_32", /* name */ 85 TRUE, /* partial_inplace */ 86 0x00000000, /* src_mask */ 87 0xffffffff, /* dst_mask */ 88 FALSE), /* pcrel_offset */ 89 90 91 /* A PC relative 8 bit relocation. */ 92 HOWTO (R_XC16X_8_PCREL, /* type */ 93 0, /* rightshift */ 94 0, /* size (0 = byte, 1 = short, 2 = long) */ 95 8, /* bitsize */ 96 TRUE, /* pc_relative */ 97 8, /* bitpos */ 98 complain_overflow_signed, /* complain_on_overflow */ 99 bfd_elf_generic_reloc, /* special_function */ 100 "R_XC16X_8_PCREL", /* name */ 101 FALSE, /* partial_inplace */ 102 0x0000, /* src_mask */ 103 0x00ff, /* dst_mask */ 104 TRUE), /* pcrel_offset */ 105 106 /* Relocation regarding page number. */ 107 HOWTO (R_XC16X_PAG, /* type */ 108 0, /* rightshift */ 109 1, /* size (0 = byte, 1 = short, 2 = long) */ 110 16, /* bitsize */ 111 FALSE, /* pc_relative */ 112 0, /* bitpos */ 113 complain_overflow_signed, /* complain_on_overflow */ 114 bfd_elf_generic_reloc, /* special_function */ 115 "R_XC16X_PAG", /* name */ 116 TRUE, /* partial_inplace */ 117 0x00000000, /* src_mask */ 118 0x0000ffff, /* dst_mask */ 119 FALSE), /* pcrel_offset */ 120 121 122 /* Relocation regarding page number. */ 123 HOWTO (R_XC16X_POF, /* type */ 124 0, /* rightshift */ 125 1, /* size (0 = byte, 1 = short, 2 = long) */ 126 16, /* bitsize */ 127 FALSE, /* pc_relative */ 128 0, /* bitpos */ 129 complain_overflow_signed, /* complain_on_overflow */ 130 bfd_elf_generic_reloc, /* special_function */ 131 "R_XC16X_POF", /* name */ 132 TRUE, /* partial_inplace */ 133 0x00000000, /* src_mask */ 134 0x0000ffff, /* dst_mask */ 135 FALSE), /* pcrel_offset */ 136 137 138 /* Relocation regarding segment number. */ 139 HOWTO (R_XC16X_SEG, /* type */ 140 0, /* rightshift */ 141 1, /* size (0 = byte, 1 = short, 2 = long) */ 142 16, /* bitsize */ 143 FALSE, /* pc_relative */ 144 0, /* bitpos */ 145 complain_overflow_signed, /* complain_on_overflow */ 146 bfd_elf_generic_reloc, /* special_function */ 147 "R_XC16X_SEG", /* name */ 148 TRUE, /* partial_inplace */ 149 0x00000000, /* src_mask */ 150 0x0000ffff, /* dst_mask */ 151 FALSE), /* pcrel_offset */ 152 153 /* Relocation regarding segment offset. */ 154 HOWTO (R_XC16X_SOF, /* type */ 155 0, /* rightshift */ 156 1, /* size (0 = byte, 1 = short, 2 = long) */ 157 16, /* bitsize */ 158 FALSE, /* pc_relative */ 159 0, /* bitpos */ 160 complain_overflow_signed, /* complain_on_overflow */ 161 bfd_elf_generic_reloc, /* special_function */ 162 "R_XC16X_SOF", /* name */ 163 TRUE, /* partial_inplace */ 164 0x00000000, /* src_mask */ 165 0x0000ffff, /* dst_mask */ 166 FALSE) /* pcrel_offset */ 167 }; 168 169 170 /* Map BFD reloc types to XC16X ELF reloc types. */ 171 172 struct xc16x_reloc_map 173 { 174 bfd_reloc_code_real_type bfd_reloc_val; 175 unsigned int xc16x_reloc_val; 176 }; 177 178 static const struct xc16x_reloc_map xc16x_reloc_map [] = 179 { 180 { BFD_RELOC_NONE, R_XC16X_NONE }, 181 { BFD_RELOC_8, R_XC16X_ABS_8 }, 182 { BFD_RELOC_16, R_XC16X_ABS_16 }, 183 { BFD_RELOC_32, R_XC16X_ABS_32 }, 184 { BFD_RELOC_8_PCREL, R_XC16X_8_PCREL }, 185 { BFD_RELOC_XC16X_PAG, R_XC16X_PAG}, 186 { BFD_RELOC_XC16X_POF, R_XC16X_POF}, 187 { BFD_RELOC_XC16X_SEG, R_XC16X_SEG}, 188 { BFD_RELOC_XC16X_SOF, R_XC16X_SOF}, 189 }; 190 191 192 /* This function is used to search for correct relocation type from 193 howto structure. */ 194 195 static reloc_howto_type * 196 xc16x_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 197 bfd_reloc_code_real_type code) 198 { 199 unsigned int i; 200 201 for (i = ARRAY_SIZE (xc16x_reloc_map); --i;) 202 if (xc16x_reloc_map [i].bfd_reloc_val == code) 203 return & xc16x_elf_howto_table [xc16x_reloc_map[i].xc16x_reloc_val]; 204 205 return NULL; 206 } 207 208 /* For a particular operand this function is 209 called to finalise the type of relocation. */ 210 211 static void 212 elf32_xc16x_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *bfd_reloc, 213 Elf_Internal_Rela *elf_reloc) 214 { 215 unsigned int r; 216 unsigned int i; 217 218 r = ELF32_R_TYPE (elf_reloc->r_info); 219 for (i = 0; i < ARRAY_SIZE (xc16x_elf_howto_table); i++) 220 if (xc16x_elf_howto_table[i].type == r) 221 { 222 bfd_reloc->howto = &xc16x_elf_howto_table[i]; 223 return; 224 } 225 abort (); 226 } 227 228 static bfd_reloc_status_type 229 elf32_xc16x_final_link_relocate (unsigned long r_type, 230 bfd *input_bfd, 231 bfd *output_bfd ATTRIBUTE_UNUSED, 232 asection *input_section ATTRIBUTE_UNUSED, 233 bfd_byte *contents, 234 bfd_vma offset, 235 bfd_vma value, 236 bfd_vma addend, 237 struct bfd_link_info *info ATTRIBUTE_UNUSED, 238 asection *sym_sec ATTRIBUTE_UNUSED, 239 int is_local ATTRIBUTE_UNUSED) 240 { 241 bfd_byte *hit_data = contents + offset; 242 bfd_vma val1; 243 244 switch (r_type) 245 { 246 case R_XC16X_NONE: 247 return bfd_reloc_ok; 248 249 case R_XC16X_ABS_16: 250 value += addend; 251 bfd_put_16 (input_bfd, value, hit_data); 252 return bfd_reloc_ok; 253 254 case R_XC16X_8_PCREL: 255 bfd_put_8 (input_bfd, value, hit_data); 256 return bfd_reloc_ok; 257 258 /* Following case is to find page number from actual 259 address for this divide value by 16k i.e. page size. */ 260 261 case R_XC16X_PAG: 262 value += addend; 263 value /= 0x4000; 264 bfd_put_16 (input_bfd, value, hit_data); 265 return bfd_reloc_ok; 266 267 /* Following case is to find page offset from actual address 268 for this take modulo of value by 16k i.e. page size. */ 269 270 case R_XC16X_POF: 271 value += addend; 272 value %= 0x4000; 273 bfd_put_16 (input_bfd, value, hit_data); 274 return bfd_reloc_ok; 275 276 /* Following case is to find segment number from actual 277 address for this divide value by 64k i.e. segment size. */ 278 279 case R_XC16X_SEG: 280 value += addend; 281 value /= 0x10000; 282 bfd_put_16 (input_bfd, value, hit_data); 283 return bfd_reloc_ok; 284 285 /* Following case is to find segment offset from actual address 286 for this take modulo of value by 64k i.e. segment size. */ 287 288 case R_XC16X_SOF: 289 value += addend; 290 value %= 0x10000; 291 bfd_put_16 (input_bfd, value, hit_data); 292 return bfd_reloc_ok; 293 294 case R_XC16X_ABS_32: 295 if (!strstr (input_section->name,".debug")) 296 { 297 value += addend; 298 val1 = value; 299 value %= 0x4000; 300 val1 /= 0x4000; 301 val1 = val1 << 16; 302 value += val1; 303 bfd_put_32 (input_bfd, value, hit_data); 304 } 305 else 306 { 307 value += addend; 308 bfd_put_32 (input_bfd, value, hit_data); 309 } 310 return bfd_reloc_ok; 311 312 default: 313 return bfd_reloc_notsupported; 314 } 315 } 316 317 static bfd_boolean 318 elf32_xc16x_relocate_section (bfd *output_bfd, 319 struct bfd_link_info *info, 320 bfd *input_bfd, 321 asection *input_section, 322 bfd_byte *contents, 323 Elf_Internal_Rela *relocs, 324 Elf_Internal_Sym *local_syms, 325 asection **local_sections) 326 { 327 Elf_Internal_Shdr *symtab_hdr; 328 struct elf_link_hash_entry **sym_hashes; 329 Elf_Internal_Rela *rel, *relend; 330 331 if (info->relocatable) 332 return TRUE; 333 334 symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 335 sym_hashes = elf_sym_hashes (input_bfd); 336 337 rel = relocs; 338 relend = relocs + input_section->reloc_count; 339 for (; rel < relend; rel++) 340 { 341 unsigned int r_type; 342 unsigned long r_symndx; 343 Elf_Internal_Sym *sym; 344 asection *sec; 345 struct elf_link_hash_entry *h; 346 bfd_vma relocation; 347 bfd_reloc_status_type r; 348 349 /* This is a final link. */ 350 r_symndx = ELF32_R_SYM (rel->r_info); 351 r_type = ELF32_R_TYPE (rel->r_info); 352 h = NULL; 353 sym = NULL; 354 sec = NULL; 355 if (r_symndx < symtab_hdr->sh_info) 356 { 357 sym = local_syms + r_symndx; 358 sec = local_sections[r_symndx]; 359 relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 360 } 361 else 362 { 363 bfd_boolean unresolved_reloc, warned; 364 365 RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 366 r_symndx, symtab_hdr, sym_hashes, 367 h, sec, relocation, 368 unresolved_reloc, warned); 369 } 370 371 r = elf32_xc16x_final_link_relocate (r_type, input_bfd, output_bfd, 372 input_section, 373 contents, rel->r_offset, 374 relocation, rel->r_addend, 375 info, sec, h == NULL); 376 } 377 378 return TRUE; 379 } 380 381 382 static void 383 elf32_xc16x_final_write_processing (bfd *abfd, 384 bfd_boolean linker ATTRIBUTE_UNUSED) 385 { 386 unsigned long val; 387 388 switch (bfd_get_mach (abfd)) 389 { 390 default: 391 case bfd_mach_xc16x: 392 val = 0x1000; 393 break; 394 395 case bfd_mach_xc16xl: 396 val = 0x1001; 397 break; 398 399 case bfd_mach_xc16xs: 400 val = 0x1002; 401 break; 402 } 403 404 elf_elfheader (abfd)->e_flags |= val; 405 } 406 407 static unsigned long 408 elf32_xc16x_mach (flagword flags) 409 { 410 switch (flags) 411 { 412 case 0x1000: 413 default: 414 return bfd_mach_xc16x; 415 416 case 0x1001: 417 return bfd_mach_xc16xl; 418 419 case 0x1002: 420 return bfd_mach_xc16xs; 421 } 422 } 423 424 425 static bfd_boolean 426 elf32_xc16x_object_p (bfd *abfd) 427 { 428 bfd_default_set_arch_mach (abfd, bfd_arch_xc16x, 429 elf32_xc16x_mach (elf_elfheader (abfd)->e_flags)); 430 return TRUE; 431 } 432 433 434 #define ELF_ARCH bfd_arch_xc16x 435 #define ELF_MACHINE_CODE EM_XC16X 436 #define ELF_MAXPAGESIZE 0x100 437 438 #define TARGET_LITTLE_SYM bfd_elf32_xc16x_vec 439 #define TARGET_LITTLE_NAME "elf32-xc16x" 440 #define elf_backend_final_write_processing elf32_xc16x_final_write_processing 441 #define elf_backend_object_p elf32_xc16x_object_p 442 #define elf_backend_can_gc_sections 1 443 #define bfd_elf32_bfd_reloc_type_lookup xc16x_reloc_type_lookup 444 #define elf_info_to_howto elf32_xc16x_info_to_howto 445 #define elf_info_to_howto_rel elf32_xc16x_info_to_howto 446 #define elf_backend_relocate_section elf32_xc16x_relocate_section 447 #define elf_backend_rela_normal 1 448 449 #include "elf32-target.h" 450