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