1 /* OR32-specific support for 32-bit ELF 2 Copyright 2002, 2004, 2005 Free Software Foundation, Inc. 3 Contributed by Ivan Guzvinec <ivang@opencores.org> 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., 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/or32.h" 26 #include "libiberty.h" 27 28 /* Try to minimize the amount of space occupied by relocation tables 29 on the ROM (not that the ROM won't be swamped by other ELF overhead). */ 30 #define USE_REL 1 31 32 /* Set the right machine number for an OR32 ELF file. */ 33 34 static bfd_boolean 35 or32_elf_object_p (bfd *abfd) 36 { 37 (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0); 38 return TRUE; 39 } 40 41 /* The final processing done just before writing out an OR32 ELF object file. 42 This gets the OR32 architecture right based on the machine number. */ 43 44 static void 45 or32_elf_final_write_processing (bfd *abfd, 46 bfd_boolean linker ATTRIBUTE_UNUSED) 47 { 48 elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH; 49 } 50 51 static bfd_reloc_status_type 52 or32_elf_32_reloc (bfd *abfd, 53 arelent *reloc_entry, 54 asymbol *symbol, 55 void * data, 56 asection *input_section, 57 bfd *output_bfd, 58 char **error_message ATTRIBUTE_UNUSED) 59 { 60 if (output_bfd != NULL) 61 { 62 unsigned long insn; 63 bfd_size_type addr = reloc_entry->address; 64 65 reloc_entry->address += input_section->output_offset; 66 67 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr); 68 insn += symbol->section->output_section->vma; 69 insn += symbol->section->output_offset; 70 insn += symbol->value; 71 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr); 72 73 return bfd_reloc_ok; 74 } 75 76 return bfd_reloc_continue; 77 } 78 79 static bfd_reloc_status_type 80 or32_elf_16_reloc (bfd *abfd, 81 arelent *reloc_entry, 82 asymbol *symbol, 83 void * data, 84 asection *input_section, 85 bfd *output_bfd, 86 char **error_message ATTRIBUTE_UNUSED) 87 { 88 if (output_bfd != NULL) 89 { 90 unsigned short insn; 91 bfd_size_type addr = reloc_entry->address; 92 93 reloc_entry->address += input_section->output_offset; 94 95 insn = bfd_get_16 (abfd, (bfd_byte *) data + addr); 96 insn += symbol->section->output_section->vma; 97 insn += symbol->section->output_offset; 98 insn += symbol->value; 99 bfd_put_16 (abfd, insn, (bfd_byte *) data + addr); 100 101 return bfd_reloc_ok; 102 } 103 104 return bfd_reloc_continue; 105 } 106 107 static bfd_reloc_status_type 108 or32_elf_8_reloc (bfd *abfd ATTRIBUTE_UNUSED, 109 arelent *reloc_entry, 110 asymbol *symbol, 111 void * data, 112 asection *input_section, 113 bfd *output_bfd, 114 char **error_message ATTRIBUTE_UNUSED) 115 { 116 if (output_bfd != NULL) 117 { 118 unsigned char insn; 119 bfd_size_type addr = reloc_entry->address; 120 121 reloc_entry->address += input_section->output_offset; 122 123 insn = bfd_get_8 (abfd, (bfd_byte *) data + addr); 124 insn += symbol->section->output_section->vma; 125 insn += symbol->section->output_offset; 126 insn += symbol->value; 127 bfd_put_8 (abfd, insn, (bfd_byte *) data + addr); 128 129 return bfd_reloc_ok; 130 } 131 132 return bfd_reloc_continue; 133 } 134 135 /* Do a R_OR32_CONSTH relocation. This has to be done in combination 136 with a R_OR32_CONST reloc, because there is a carry from the LO16 to 137 the HI16. Here we just save the information we need; we do the 138 actual relocation when we see the LO16. OR32 ELF requires that the 139 LO16 immediately follow the HI16. As a GNU extension, we permit an 140 arbitrary number of HI16 relocs to be associated with a single LO16 141 reloc. This extension permits gcc to output the HI and LO relocs 142 itself. This code is copied from the elf32-mips.c. */ 143 144 struct or32_consth 145 { 146 struct or32_consth *next; 147 bfd_byte *addr; 148 bfd_vma addend; 149 }; 150 151 /* FIXME: This should not be a static variable. */ 152 153 static struct or32_consth *or32_consth_list; 154 155 static bfd_reloc_status_type 156 or32_elf_consth_reloc (bfd *abfd ATTRIBUTE_UNUSED, 157 arelent *reloc_entry, 158 asymbol *symbol, 159 void * data, 160 asection *input_section, 161 bfd *output_bfd, 162 char **error_message ATTRIBUTE_UNUSED) 163 { 164 bfd_reloc_status_type ret; 165 bfd_vma relocation; 166 struct or32_consth *n; 167 168 ret = bfd_reloc_ok; 169 170 if (bfd_is_und_section (symbol->section) 171 && output_bfd == NULL) 172 ret = bfd_reloc_undefined; 173 174 if (bfd_is_com_section (symbol->section)) 175 relocation = 0; 176 else 177 relocation = symbol->value; 178 179 relocation += symbol->section->output_section->vma; 180 relocation += symbol->section->output_offset; 181 relocation += reloc_entry->addend; 182 183 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 184 return bfd_reloc_outofrange; 185 186 /* Save the information, and let LO16 do the actual relocation. */ 187 n = bfd_malloc (sizeof *n); 188 if (n == NULL) 189 return bfd_reloc_outofrange; 190 n->addr = (bfd_byte *) data + reloc_entry->address; 191 n->addend = relocation; 192 n->next = or32_consth_list; 193 or32_consth_list = n; 194 195 if (output_bfd != NULL) 196 reloc_entry->address += input_section->output_offset; 197 198 return ret; 199 } 200 201 /* Do a R_OR32_CONST relocation. This is a straightforward 16 bit 202 inplace relocation; this function exists in order to do the 203 R_OR32_CONSTH relocation described above. */ 204 205 static bfd_reloc_status_type 206 or32_elf_const_reloc (bfd *abfd, 207 arelent *reloc_entry, 208 asymbol *symbol, 209 void * data, 210 asection *input_section, 211 bfd *output_bfd, 212 char **error_message) 213 { 214 if (or32_consth_list != NULL) 215 { 216 struct or32_consth *l; 217 218 l = or32_consth_list; 219 while (l != NULL) 220 { 221 unsigned long insn; 222 unsigned long val; 223 unsigned long vallo; 224 struct or32_consth *next; 225 226 /* Do the HI16 relocation. Note that we actually don't need 227 to know anything about the LO16 itself, except where to 228 find the low 16 bits of the addend needed by the LO16. */ 229 insn = bfd_get_32 (abfd, l->addr); 230 vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) 231 & 0xffff); 232 val = ((insn & 0xffff) << 16) + vallo; 233 val += l->addend; 234 235 insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); 236 bfd_put_32 (abfd, insn, l->addr); 237 238 next = l->next; 239 free (l); 240 l = next; 241 } 242 243 or32_consth_list = NULL; 244 } 245 246 if (output_bfd != NULL) 247 { 248 unsigned long insn, tmp; 249 bfd_size_type addr = reloc_entry->address; 250 251 reloc_entry->address += input_section->output_offset; 252 253 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr); 254 tmp = insn & 0x0000ffff; 255 tmp += symbol->section->output_section->vma; 256 tmp += symbol->section->output_offset; 257 tmp += symbol->value; 258 insn = (insn & 0xffff0000) | (tmp & 0x0000ffff); 259 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr); 260 261 return bfd_reloc_ok; 262 } 263 264 /* Now do the LO16 reloc in the usual way. */ 265 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 266 input_section, output_bfd, error_message); 267 } 268 269 static bfd_reloc_status_type 270 or32_elf_jumptarg_reloc (bfd *abfd, 271 arelent *reloc_entry, 272 asymbol *symbol ATTRIBUTE_UNUSED, 273 void * data, 274 asection *input_section, 275 bfd *output_bfd, 276 char **error_message ATTRIBUTE_UNUSED) 277 { 278 if (output_bfd != NULL) 279 { 280 unsigned long insn, tmp; 281 bfd_size_type addr = reloc_entry->address; 282 283 reloc_entry->address += input_section->output_offset; 284 285 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr); 286 tmp = insn | 0xfc000000; 287 tmp -= (input_section->output_offset >> 2); 288 insn = (insn & 0xfc000000) | (tmp & 0x03ffffff); 289 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr); 290 291 return bfd_reloc_ok; 292 } 293 294 return bfd_reloc_continue; 295 } 296 297 static reloc_howto_type elf_or32_howto_table[] = 298 { 299 /* This reloc does nothing. */ 300 HOWTO (R_OR32_NONE, /* type */ 301 0, /* rightshift */ 302 2, /* size (0 = byte, 1 = short, 2 = long) */ 303 32, /* bitsize */ 304 FALSE, /* pc_relative */ 305 0, /* bitpos */ 306 complain_overflow_bitfield, /* complain_on_overflow */ 307 bfd_elf_generic_reloc, /* special_function */ 308 "R_OR32_NONE", /* name */ 309 FALSE, /* partial_inplace */ 310 0, /* src_mask */ 311 0, /* dst_mask */ 312 FALSE), /* pcrel_offset */ 313 314 /* A standard 32 bit relocation. */ 315 HOWTO (R_OR32_32, /* type */ 316 0, /* rightshift */ 317 2, /* size (0 = byte, 1 = short, 2 = long) */ 318 32, /* bitsize */ 319 FALSE, /* pc_relative */ 320 0, /* bitpos */ 321 complain_overflow_bitfield, /* complain_on_overflow */ 322 or32_elf_32_reloc, /* special_function */ 323 "R_OR32_32", /* name */ 324 FALSE, /* partial_inplace */ 325 0xffffffff, /* src_mask */ 326 0xffffffff, /* dst_mask */ 327 FALSE), /* pcrel_offset */ 328 329 /* A standard 16 bit relocation. */ 330 HOWTO (R_OR32_16, /* type */ 331 0, /* rightshift */ 332 1, /* size (0 = byte, 1 = short, 2 = long) */ 333 16, /* bitsize */ 334 FALSE, /* pc_relative */ 335 0, /* bitpos */ 336 complain_overflow_bitfield, /* complain_on_overflow */ 337 or32_elf_16_reloc, /* special_function */ 338 "R_OR32_16", /* name */ 339 FALSE, /* partial_inplace */ 340 0x0000ffff, /* src_mask */ 341 0x0000ffff, /* dst_mask */ 342 FALSE), /* pcrel_offset */ 343 344 /* A standard 8 bit relocation. */ 345 HOWTO (R_OR32_8, /* type */ 346 0, /* rightshift */ 347 0, /* size (0 = byte, 1 = short, 2 = long) */ 348 8, /* bitsize */ 349 FALSE, /* pc_relative */ 350 0, /* bitpos */ 351 complain_overflow_bitfield, /* complain_on_overflow */ 352 or32_elf_8_reloc, /* special_function */ 353 "R_OR32_8", /* name */ 354 FALSE, /* partial_inplace */ 355 0x000000ff, /* src_mask */ 356 0x000000ff, /* dst_mask */ 357 FALSE), /* pcrel_offset */ 358 359 /* A standard low 16 bit relocation. */ 360 HOWTO (R_OR32_CONST, /* type */ 361 0, /* rightshift */ 362 2, /* size (0 = byte, 1 = short, 2 = long) */ 363 16, /* bitsize */ 364 FALSE, /* pc_relative */ 365 0, /* bitpos */ 366 complain_overflow_dont, /* complain_on_overflow */ 367 or32_elf_const_reloc, /* special_function */ 368 "R_OR32_CONST", /* name */ 369 FALSE, /* partial_inplace */ 370 0x0000ffff, /* src_mask */ 371 0x0000ffff, /* dst_mask */ 372 FALSE), /* pcrel_offset */ 373 374 /* A standard high 16 bit relocation. */ 375 HOWTO (R_OR32_CONSTH, /* type */ 376 16, /* rightshift */ 377 2, /* size (0 = byte, 1 = short, 2 = long) */ 378 16, /* bitsize */ 379 TRUE, /* pc_relative */ 380 0, /* bitpos */ 381 complain_overflow_dont, /* complain_on_overflow */ 382 or32_elf_consth_reloc, /* special_function */ 383 "R_OR32_CONSTH", /* name */ 384 FALSE, /* partial_inplace */ 385 0xffff0000, /* src_mask */ 386 0x0000ffff, /* dst_mask */ 387 FALSE), /* pcrel_offset */ 388 389 /* A standard branch relocation. */ 390 HOWTO (R_OR32_JUMPTARG, /* type */ 391 2, /* rightshift */ 392 2, /* size (0 = byte, 1 = short, 2 = long) */ 393 28, /* bitsize */ 394 TRUE, /* pc_relative */ 395 0, /* bitpos */ 396 complain_overflow_signed, /* complain_on_overflow */ 397 or32_elf_jumptarg_reloc,/* special_function */ 398 "R_OR32_JUMPTARG", /* name */ 399 FALSE, /* partial_inplace */ 400 0, /* src_mask */ 401 0x03ffffff, /* dst_mask */ 402 TRUE), /* pcrel_offset */ 403 404 /* GNU extension to record C++ vtable hierarchy. */ 405 HOWTO (R_OR32_GNU_VTINHERIT, /* type */ 406 0, /* rightshift */ 407 2, /* size (0 = byte, 1 = short, 2 = long) */ 408 0, /* bitsize */ 409 FALSE, /* pc_relative */ 410 0, /* bitpos */ 411 complain_overflow_dont, /* complain_on_overflow */ 412 NULL, /* special_function */ 413 "R_OR32_GNU_VTINHERIT", /* name */ 414 FALSE, /* partial_inplace */ 415 0, /* src_mask */ 416 0, /* dst_mask */ 417 FALSE), /* pcrel_offset */ 418 419 /* GNU extension to record C++ vtable member usage. */ 420 HOWTO (R_OR32_GNU_VTENTRY, /* type */ 421 0, /* rightshift */ 422 2, /* size (0 = byte, 1 = short, 2 = long) */ 423 0, /* bitsize */ 424 FALSE, /* pc_relative */ 425 0, /* bitpos */ 426 complain_overflow_dont, /* complain_on_overflow */ 427 _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 428 "R_OR32_GNU_VTENTRY", /* name */ 429 FALSE, /* partial_inplace */ 430 0, /* src_mask */ 431 0, /* dst_mask */ 432 FALSE), /* pcrel_offset */ 433 }; 434 435 /* Map BFD reloc types to OR32 ELF reloc types. */ 436 437 struct or32_reloc_map 438 { 439 bfd_reloc_code_real_type bfd_reloc_val; 440 unsigned char elf_reloc_val; 441 }; 442 443 static const struct or32_reloc_map or32_reloc_map[] = 444 { 445 { BFD_RELOC_NONE, R_OR32_NONE }, 446 { BFD_RELOC_32, R_OR32_32 }, 447 { BFD_RELOC_16, R_OR32_16 }, 448 { BFD_RELOC_8, R_OR32_8 }, 449 { BFD_RELOC_LO16, R_OR32_CONST }, 450 { BFD_RELOC_HI16, R_OR32_CONSTH }, 451 { BFD_RELOC_32_GOT_PCREL, R_OR32_JUMPTARG }, 452 { BFD_RELOC_VTABLE_INHERIT, R_OR32_GNU_VTINHERIT }, 453 { BFD_RELOC_VTABLE_ENTRY, R_OR32_GNU_VTENTRY }, 454 }; 455 456 static reloc_howto_type * 457 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 458 bfd_reloc_code_real_type code) 459 { 460 unsigned int i; 461 462 for (i = ARRAY_SIZE (or32_reloc_map); i--;) 463 if (or32_reloc_map[i].bfd_reloc_val == code) 464 return &elf_or32_howto_table[or32_reloc_map[i].elf_reloc_val]; 465 466 return NULL; 467 } 468 469 /* Set the howto pointer for an OR32 ELF reloc. */ 470 471 static void 472 or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, 473 arelent *cache_ptr, 474 Elf_Internal_Rela *dst) 475 { 476 unsigned int r_type; 477 478 r_type = ELF32_R_TYPE (dst->r_info); 479 BFD_ASSERT (r_type < (unsigned int) R_OR32_max); 480 cache_ptr->howto = &elf_or32_howto_table[r_type]; 481 } 482 483 #define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec 484 #define TARGET_LITTLE_NAME "elf32-littleor32" 485 #define TARGET_BIG_SYM bfd_elf32_or32_big_vec 486 #define TARGET_BIG_NAME "elf32-or32" 487 #define ELF_ARCH bfd_arch_or32 488 #define ELF_MACHINE_CODE EM_OR32 489 #define ELF_MAXPAGESIZE 0x1000 490 491 #define elf_info_to_howto 0 492 #define elf_info_to_howto_rel or32_info_to_howto_rel 493 #define elf_backend_object_p or32_elf_object_p 494 #define elf_backend_final_write_processing \ 495 or32_elf_final_write_processing 496 497 #include "elf32-target.h" 498