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