1 1.1 christos /* FR30-specific support for 32-bit ELF. 2 1.11 christos Copyright (C) 1998-2024 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos This file is part of BFD, the Binary File Descriptor library. 5 1.1 christos 6 1.1 christos This program is free software; you can redistribute it and/or modify 7 1.1 christos it under the terms of the GNU General Public License as published by 8 1.1 christos the Free Software Foundation; either version 3 of the License, or 9 1.1 christos (at your option) any later version. 10 1.1 christos 11 1.1 christos This program is distributed in the hope that it will be useful, 12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 1.1 christos GNU General Public License for more details. 15 1.1 christos 16 1.1 christos You should have received a copy of the GNU General Public License 17 1.1 christos along with this program; if not, write to the Free Software 18 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 1.1 christos MA 02110-1301, USA. */ 20 1.1 christos 21 1.1 christos #include "sysdep.h" 22 1.1 christos #include "bfd.h" 23 1.1 christos #include "libbfd.h" 24 1.1 christos #include "elf-bfd.h" 25 1.1 christos #include "elf/fr30.h" 26 1.1 christos 27 1.1 christos /* Forward declarations. */ 28 1.1 christos static bfd_reloc_status_type 29 1.1 christos fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data, 30 1.1 christos asection *, bfd *, char **error_message); 31 1.1 christos static bfd_reloc_status_type 32 1.1 christos fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *, 33 1.1 christos asection *, bfd *, char **); 34 1.1 christos 35 1.1 christos static reloc_howto_type fr30_elf_howto_table [] = 36 1.1 christos { 37 1.1 christos /* This reloc does nothing. */ 38 1.1 christos HOWTO (R_FR30_NONE, /* type */ 39 1.1 christos 0, /* rightshift */ 40 1.10 christos 0, /* size */ 41 1.5 christos 0, /* bitsize */ 42 1.10 christos false, /* pc_relative */ 43 1.1 christos 0, /* bitpos */ 44 1.5 christos complain_overflow_dont, /* complain_on_overflow */ 45 1.1 christos bfd_elf_generic_reloc, /* special_function */ 46 1.1 christos "R_FR30_NONE", /* name */ 47 1.10 christos false, /* partial_inplace */ 48 1.1 christos 0, /* src_mask */ 49 1.1 christos 0, /* dst_mask */ 50 1.10 christos false), /* pcrel_offset */ 51 1.1 christos 52 1.1 christos /* An 8 bit absolute relocation. */ 53 1.1 christos HOWTO (R_FR30_8, /* type */ 54 1.1 christos 0, /* rightshift */ 55 1.10 christos 2, /* size */ 56 1.1 christos 8, /* bitsize */ 57 1.10 christos false, /* pc_relative */ 58 1.1 christos 4, /* bitpos */ 59 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 60 1.1 christos bfd_elf_generic_reloc, /* special_function */ 61 1.1 christos "R_FR30_8", /* name */ 62 1.10 christos false, /* partial_inplace */ 63 1.1 christos 0x0000, /* src_mask */ 64 1.1 christos 0x0ff0, /* dst_mask */ 65 1.10 christos false), /* pcrel_offset */ 66 1.1 christos 67 1.1 christos /* A 20 bit absolute relocation. */ 68 1.1 christos HOWTO (R_FR30_20, /* type */ 69 1.1 christos 0, /* rightshift */ 70 1.10 christos 4, /* size */ 71 1.1 christos 20, /* bitsize */ 72 1.10 christos false, /* pc_relative */ 73 1.1 christos 0, /* bitpos */ 74 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 75 1.1 christos fr30_elf_i20_reloc, /* special_function */ 76 1.1 christos "R_FR30_20", /* name */ 77 1.10 christos false, /* partial_inplace */ 78 1.1 christos 0x00000000, /* src_mask */ 79 1.1 christos 0x00f0ffff, /* dst_mask */ 80 1.10 christos false), /* pcrel_offset */ 81 1.1 christos 82 1.1 christos /* A 32 bit absolute relocation. */ 83 1.1 christos HOWTO (R_FR30_32, /* type */ 84 1.1 christos 0, /* rightshift */ 85 1.10 christos 4, /* size */ 86 1.1 christos 32, /* bitsize */ 87 1.10 christos false, /* pc_relative */ 88 1.1 christos 0, /* bitpos */ 89 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 90 1.1 christos bfd_elf_generic_reloc, /* special_function */ 91 1.1 christos "R_FR30_32", /* name */ 92 1.10 christos false, /* partial_inplace */ 93 1.1 christos 0x00000000, /* src_mask */ 94 1.1 christos 0xffffffff, /* dst_mask */ 95 1.10 christos false), /* pcrel_offset */ 96 1.1 christos 97 1.1 christos /* A 32 bit into 48 bits absolute relocation. */ 98 1.1 christos HOWTO (R_FR30_48, /* type */ 99 1.1 christos 0, /* rightshift */ 100 1.10 christos 4, /* size */ 101 1.1 christos 32, /* bitsize */ 102 1.10 christos false, /* pc_relative */ 103 1.1 christos 0, /* bitpos */ 104 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 105 1.1 christos fr30_elf_i32_reloc, /* special_function */ 106 1.1 christos "R_FR30_48", /* name */ 107 1.10 christos false, /* partial_inplace */ 108 1.1 christos 0x00000000, /* src_mask */ 109 1.1 christos 0xffffffff, /* dst_mask */ 110 1.10 christos false), /* pcrel_offset */ 111 1.1 christos 112 1.1 christos /* A 6 bit absolute relocation. */ 113 1.1 christos HOWTO (R_FR30_6_IN_4, /* type */ 114 1.1 christos 2, /* rightshift */ 115 1.10 christos 2, /* size */ 116 1.1 christos 6, /* bitsize */ 117 1.10 christos false, /* pc_relative */ 118 1.1 christos 4, /* bitpos */ 119 1.1 christos complain_overflow_unsigned, /* complain_on_overflow */ 120 1.1 christos bfd_elf_generic_reloc, /* special_function */ 121 1.1 christos "R_FR30_6_IN_4", /* name */ 122 1.10 christos false, /* partial_inplace */ 123 1.1 christos 0x0000, /* src_mask */ 124 1.1 christos 0x00f0, /* dst_mask */ 125 1.10 christos false), /* pcrel_offset */ 126 1.1 christos 127 1.1 christos /* An 8 bit absolute relocation. */ 128 1.1 christos HOWTO (R_FR30_8_IN_8, /* type */ 129 1.1 christos 0, /* rightshift */ 130 1.10 christos 2, /* size */ 131 1.1 christos 8, /* bitsize */ 132 1.10 christos false, /* pc_relative */ 133 1.1 christos 4, /* bitpos */ 134 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 135 1.1 christos bfd_elf_generic_reloc,/* special_function */ 136 1.1 christos "R_FR30_8_IN_8", /* name */ 137 1.10 christos false, /* partial_inplace */ 138 1.1 christos 0x0000, /* src_mask */ 139 1.1 christos 0x0ff0, /* dst_mask */ 140 1.10 christos false), /* pcrel_offset */ 141 1.1 christos 142 1.1 christos /* A 9 bit absolute relocation. */ 143 1.1 christos HOWTO (R_FR30_9_IN_8, /* type */ 144 1.1 christos 1, /* rightshift */ 145 1.10 christos 2, /* size */ 146 1.1 christos 9, /* bitsize */ 147 1.10 christos false, /* pc_relative */ 148 1.1 christos 4, /* bitpos */ 149 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 150 1.1 christos bfd_elf_generic_reloc,/* special_function */ 151 1.1 christos "R_FR30_9_IN_8", /* name */ 152 1.10 christos false, /* partial_inplace */ 153 1.1 christos 0x0000, /* src_mask */ 154 1.1 christos 0x0ff0, /* dst_mask */ 155 1.10 christos false), /* pcrel_offset */ 156 1.1 christos 157 1.1 christos /* A 10 bit absolute relocation. */ 158 1.1 christos HOWTO (R_FR30_10_IN_8, /* type */ 159 1.1 christos 2, /* rightshift */ 160 1.10 christos 2, /* size */ 161 1.1 christos 10, /* bitsize */ 162 1.10 christos false, /* pc_relative */ 163 1.1 christos 4, /* bitpos */ 164 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 165 1.1 christos bfd_elf_generic_reloc,/* special_function */ 166 1.1 christos "R_FR30_10_IN_8", /* name */ 167 1.10 christos false, /* partial_inplace */ 168 1.1 christos 0x0000, /* src_mask */ 169 1.1 christos 0x0ff0, /* dst_mask */ 170 1.10 christos false), /* pcrel_offset */ 171 1.1 christos 172 1.1 christos /* A PC relative 9 bit relocation, right shifted by 1. */ 173 1.1 christos HOWTO (R_FR30_9_PCREL, /* type */ 174 1.1 christos 1, /* rightshift */ 175 1.10 christos 2, /* size */ 176 1.1 christos 9, /* bitsize */ 177 1.10 christos true, /* pc_relative */ 178 1.1 christos 0, /* bitpos */ 179 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 180 1.1 christos bfd_elf_generic_reloc, /* special_function */ 181 1.1 christos "R_FR30_9_PCREL", /* name */ 182 1.10 christos false, /* partial_inplace */ 183 1.1 christos 0x0000, /* src_mask */ 184 1.1 christos 0x00ff, /* dst_mask */ 185 1.10 christos false), /* pcrel_offset */ 186 1.1 christos 187 1.1 christos /* A PC relative 12 bit relocation, right shifted by 1. */ 188 1.1 christos HOWTO (R_FR30_12_PCREL, /* type */ 189 1.1 christos 1, /* rightshift */ 190 1.10 christos 2, /* size */ 191 1.1 christos 12, /* bitsize */ 192 1.10 christos true, /* pc_relative */ 193 1.1 christos 0, /* bitpos */ 194 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 195 1.1 christos bfd_elf_generic_reloc, /* special_function */ 196 1.1 christos "R_FR30_12_PCREL", /* name */ 197 1.10 christos false, /* partial_inplace */ 198 1.1 christos 0x0000, /* src_mask */ 199 1.1 christos 0x07ff, /* dst_mask */ 200 1.10 christos false), /* pcrel_offset */ 201 1.1 christos /* GNU extension to record C++ vtable hierarchy */ 202 1.1 christos HOWTO (R_FR30_GNU_VTINHERIT, /* type */ 203 1.8 christos 0, /* rightshift */ 204 1.10 christos 4, /* size */ 205 1.8 christos 0, /* bitsize */ 206 1.10 christos false, /* pc_relative */ 207 1.8 christos 0, /* bitpos */ 208 1.8 christos complain_overflow_dont, /* complain_on_overflow */ 209 1.8 christos NULL, /* special_function */ 210 1.8 christos "R_FR30_GNU_VTINHERIT", /* name */ 211 1.10 christos false, /* partial_inplace */ 212 1.8 christos 0, /* src_mask */ 213 1.8 christos 0, /* dst_mask */ 214 1.10 christos false), /* pcrel_offset */ 215 1.1 christos 216 1.1 christos /* GNU extension to record C++ vtable member usage */ 217 1.8 christos HOWTO (R_FR30_GNU_VTENTRY, /* type */ 218 1.8 christos 0, /* rightshift */ 219 1.10 christos 4, /* size */ 220 1.8 christos 0, /* bitsize */ 221 1.10 christos false, /* pc_relative */ 222 1.8 christos 0, /* bitpos */ 223 1.8 christos complain_overflow_dont, /* complain_on_overflow */ 224 1.8 christos _bfd_elf_rel_vtable_reloc_fn, /* special_function */ 225 1.8 christos "R_FR30_GNU_VTENTRY", /* name */ 226 1.10 christos false, /* partial_inplace */ 227 1.8 christos 0, /* src_mask */ 228 1.8 christos 0, /* dst_mask */ 229 1.10 christos false), /* pcrel_offset */ 230 1.1 christos }; 231 1.1 christos 232 1.1 christos /* Utility to actually perform an R_FR30_20 reloc. */ 234 1.1 christos 235 1.1 christos static bfd_reloc_status_type 236 1.1 christos fr30_elf_i20_reloc (bfd *abfd, 237 1.1 christos arelent *reloc_entry, 238 1.1 christos asymbol *symbol, 239 1.1 christos void * data, 240 1.1 christos asection *input_section, 241 1.1 christos bfd *output_bfd, 242 1.1 christos char **error_message ATTRIBUTE_UNUSED) 243 1.1 christos { 244 1.1 christos bfd_vma relocation; 245 1.1 christos unsigned long x; 246 1.1 christos 247 1.1 christos /* This part is from bfd_elf_generic_reloc. */ 248 1.1 christos if (output_bfd != (bfd *) NULL 249 1.1 christos && (symbol->flags & BSF_SECTION_SYM) == 0 250 1.1 christos && (! reloc_entry->howto->partial_inplace 251 1.1 christos || reloc_entry->addend == 0)) 252 1.1 christos { 253 1.1 christos reloc_entry->address += input_section->output_offset; 254 1.1 christos return bfd_reloc_ok; 255 1.1 christos } 256 1.1 christos 257 1.1 christos if (output_bfd != NULL) 258 1.1 christos /* FIXME: See bfd_perform_relocation. Is this right? */ 259 1.1 christos return bfd_reloc_ok; 260 1.1 christos 261 1.1 christos relocation = 262 1.1 christos symbol->value 263 1.1 christos + symbol->section->output_section->vma 264 1.1 christos + symbol->section->output_offset 265 1.1 christos + reloc_entry->addend; 266 1.1 christos 267 1.1 christos if (relocation > (((bfd_vma) 1 << 20) - 1)) 268 1.1 christos return bfd_reloc_overflow; 269 1.1 christos 270 1.1 christos x = bfd_get_32 (abfd, (char *) data + reloc_entry->address); 271 1.1 christos x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4); 272 1.1 christos bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address); 273 1.1 christos 274 1.1 christos return bfd_reloc_ok; 275 1.1 christos } 276 1.1 christos 277 1.1 christos /* Utility to actually perform a R_FR30_48 reloc. */ 279 1.1 christos 280 1.1 christos static bfd_reloc_status_type 281 1.1 christos fr30_elf_i32_reloc (bfd *abfd, 282 1.1 christos arelent *reloc_entry, 283 1.1 christos asymbol *symbol, 284 1.1 christos void * data, 285 1.1 christos asection *input_section, 286 1.1 christos bfd *output_bfd, 287 1.1 christos char **error_message ATTRIBUTE_UNUSED) 288 1.1 christos { 289 1.1 christos bfd_vma relocation; 290 1.1 christos 291 1.1 christos /* This part is from bfd_elf_generic_reloc. */ 292 1.1 christos if (output_bfd != (bfd *) NULL 293 1.1 christos && (symbol->flags & BSF_SECTION_SYM) == 0 294 1.1 christos && (! reloc_entry->howto->partial_inplace 295 1.1 christos || reloc_entry->addend == 0)) 296 1.1 christos { 297 1.1 christos reloc_entry->address += input_section->output_offset; 298 1.1 christos return bfd_reloc_ok; 299 1.1 christos } 300 1.1 christos 301 1.1 christos if (output_bfd != NULL) 302 1.1 christos /* FIXME: See bfd_perform_relocation. Is this right? */ 303 1.1 christos return bfd_reloc_ok; 304 1.1 christos 305 1.1 christos relocation = 306 1.1 christos symbol->value 307 1.1 christos + symbol->section->output_section->vma 308 1.1 christos + symbol->section->output_offset 309 1.1 christos + reloc_entry->addend; 310 1.1 christos 311 1.1 christos bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2); 312 1.1 christos 313 1.1 christos return bfd_reloc_ok; 314 1.1 christos } 315 1.1 christos 316 1.1 christos /* Map BFD reloc types to FR30 ELF reloc types. */ 318 1.1 christos 319 1.1 christos struct fr30_reloc_map 320 1.1 christos { 321 1.1 christos bfd_reloc_code_real_type bfd_reloc_val; 322 1.1 christos unsigned int fr30_reloc_val; 323 1.1 christos }; 324 1.8 christos 325 1.8 christos static const struct fr30_reloc_map fr30_reloc_map [] = 326 1.8 christos { 327 1.8 christos { BFD_RELOC_NONE, R_FR30_NONE }, 328 1.8 christos { BFD_RELOC_8, R_FR30_8 }, 329 1.1 christos { BFD_RELOC_FR30_20, R_FR30_20 }, 330 1.1 christos { BFD_RELOC_32, R_FR30_32 }, 331 1.1 christos { BFD_RELOC_FR30_48, R_FR30_48 }, 332 1.1 christos { BFD_RELOC_FR30_6_IN_4, R_FR30_6_IN_4 }, 333 1.1 christos { BFD_RELOC_FR30_8_IN_8, R_FR30_8_IN_8 }, 334 1.1 christos { BFD_RELOC_FR30_9_IN_8, R_FR30_9_IN_8 }, 335 1.1 christos { BFD_RELOC_FR30_10_IN_8, R_FR30_10_IN_8 }, 336 1.1 christos { BFD_RELOC_FR30_9_PCREL, R_FR30_9_PCREL }, 337 1.1 christos { BFD_RELOC_FR30_12_PCREL, R_FR30_12_PCREL }, 338 1.1 christos { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT }, 339 1.1 christos { BFD_RELOC_VTABLE_ENTRY, R_FR30_GNU_VTENTRY }, 340 1.1 christos }; 341 1.1 christos 342 1.1 christos static reloc_howto_type * 343 1.1 christos fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 344 1.1 christos bfd_reloc_code_real_type code) 345 1.1 christos { 346 1.5 christos unsigned int i; 347 1.1 christos 348 1.1 christos for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]); 349 1.1 christos i--;) 350 1.1 christos if (fr30_reloc_map [i].bfd_reloc_val == code) 351 1.1 christos return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val]; 352 1.1 christos 353 1.1 christos return NULL; 354 1.1 christos } 355 1.1 christos 356 1.1 christos static reloc_howto_type * 357 1.1 christos fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) 358 1.1 christos { 359 1.1 christos unsigned int i; 360 1.1 christos 361 1.1 christos for (i = 0; 362 1.1 christos i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]); 363 1.1 christos i++) 364 1.1 christos if (fr30_elf_howto_table[i].name != NULL 365 1.1 christos && strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0) 366 1.1 christos return &fr30_elf_howto_table[i]; 367 1.1 christos 368 1.1 christos return NULL; 369 1.1 christos } 370 1.10 christos 371 1.1 christos /* Set the howto pointer for an FR30 ELF reloc. */ 372 1.1 christos 373 1.1 christos static bool 374 1.1 christos fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, 375 1.1 christos arelent *cache_ptr, 376 1.1 christos Elf_Internal_Rela *dst) 377 1.1 christos { 378 1.3 christos unsigned int r_type; 379 1.3 christos 380 1.7 christos r_type = ELF32_R_TYPE (dst->r_info); 381 1.8 christos if (r_type >= (unsigned int) R_FR30_max) 382 1.8 christos { 383 1.8 christos /* xgettext:c-format */ 384 1.10 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"), 385 1.3 christos abfd, r_type); 386 1.1 christos bfd_set_error (bfd_error_bad_value); 387 1.10 christos return false; 388 1.1 christos } 389 1.1 christos cache_ptr->howto = & fr30_elf_howto_table [r_type]; 390 1.1 christos return true; 391 1.1 christos } 392 1.1 christos 393 1.1 christos /* Perform a single relocation. By default we use the standard BFD 395 1.1 christos routines, but a few relocs, we have to do them ourselves. */ 396 1.1 christos 397 1.1 christos static bfd_reloc_status_type 398 1.1 christos fr30_final_link_relocate (reloc_howto_type *howto, 399 1.1 christos bfd *input_bfd, 400 1.1 christos asection *input_section, 401 1.1 christos bfd_byte *contents, 402 1.1 christos Elf_Internal_Rela *rel, 403 1.1 christos bfd_vma relocation) 404 1.1 christos { 405 1.1 christos bfd_reloc_status_type r = bfd_reloc_ok; 406 1.1 christos bfd_vma x; 407 1.1 christos bfd_signed_vma srel; 408 1.1 christos 409 1.1 christos switch (howto->type) 410 1.1 christos { 411 1.1 christos case R_FR30_20: 412 1.1 christos contents += rel->r_offset; 413 1.1 christos relocation += rel->r_addend; 414 1.1 christos 415 1.1 christos if (relocation > ((1 << 20) - 1)) 416 1.1 christos return bfd_reloc_overflow; 417 1.1 christos 418 1.1 christos x = bfd_get_32 (input_bfd, contents); 419 1.1 christos x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4); 420 1.1 christos bfd_put_32 (input_bfd, x, contents); 421 1.1 christos break; 422 1.1 christos 423 1.1 christos case R_FR30_48: 424 1.1 christos contents += rel->r_offset + 2; 425 1.1 christos relocation += rel->r_addend; 426 1.1 christos bfd_put_32 (input_bfd, relocation, contents); 427 1.1 christos break; 428 1.1 christos 429 1.1 christos case R_FR30_9_PCREL: 430 1.1 christos contents += rel->r_offset + 1; 431 1.1 christos srel = (bfd_signed_vma) relocation; 432 1.1 christos srel += rel->r_addend; 433 1.1 christos srel -= rel->r_offset; 434 1.1 christos srel -= 2; /* Branch instructions add 2 to the PC... */ 435 1.1 christos srel -= (input_section->output_section->vma + 436 1.1 christos input_section->output_offset); 437 1.1 christos 438 1.1 christos if (srel & 1) 439 1.1 christos return bfd_reloc_outofrange; 440 1.1 christos if (srel > ((1 << 8) - 1) || (srel < - (1 << 8))) 441 1.1 christos return bfd_reloc_overflow; 442 1.1 christos 443 1.1 christos bfd_put_8 (input_bfd, srel >> 1, contents); 444 1.1 christos break; 445 1.1 christos 446 1.1 christos case R_FR30_12_PCREL: 447 1.1 christos contents += rel->r_offset; 448 1.1 christos srel = (bfd_signed_vma) relocation; 449 1.1 christos srel += rel->r_addend; 450 1.1 christos srel -= rel->r_offset; 451 1.1 christos srel -= 2; /* Branch instructions add 2 to the PC... */ 452 1.1 christos srel -= (input_section->output_section->vma + 453 1.1 christos input_section->output_offset); 454 1.1 christos 455 1.1 christos if (srel & 1) 456 1.1 christos return bfd_reloc_outofrange; 457 1.1 christos if (srel > ((1 << 11) - 1) || (srel < - (1 << 11))) 458 1.1 christos return bfd_reloc_overflow; 459 1.1 christos 460 1.1 christos x = bfd_get_16 (input_bfd, contents); 461 1.1 christos x = (x & 0xf800) | ((srel >> 1) & 0x7ff); 462 1.1 christos bfd_put_16 (input_bfd, x, contents); 463 1.1 christos break; 464 1.1 christos 465 1.1 christos default: 466 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd, input_section, 467 1.1 christos contents, rel->r_offset, 468 1.1 christos relocation, rel->r_addend); 469 1.1 christos } 470 1.1 christos 471 1.1 christos return r; 472 1.1 christos } 473 1.1 christos 474 1.1 christos /* Relocate an FR30 ELF section. 476 1.1 christos 477 1.1 christos The RELOCATE_SECTION function is called by the new ELF backend linker 478 1.1 christos to handle the relocations for a section. 479 1.1 christos 480 1.1 christos The relocs are always passed as Rela structures; if the section 481 1.1 christos actually uses Rel structures, the r_addend field will always be 482 1.1 christos zero. 483 1.1 christos 484 1.1 christos This function is responsible for adjusting the section contents as 485 1.1 christos necessary, and (if using Rela relocs and generating a relocatable 486 1.1 christos output file) adjusting the reloc addend as necessary. 487 1.1 christos 488 1.1 christos This function does not have to worry about setting the reloc 489 1.1 christos address or the reloc symbol index. 490 1.1 christos 491 1.1 christos LOCAL_SYMS is a pointer to the swapped in local symbols. 492 1.1 christos 493 1.1 christos LOCAL_SECTIONS is an array giving the section in the input file 494 1.1 christos corresponding to the st_shndx field of each local symbol. 495 1.1 christos 496 1.1 christos The global hash table entry for the global symbols can be found 497 1.1 christos via elf_sym_hashes (input_bfd). 498 1.1 christos 499 1.1 christos When generating relocatable output, this function must handle 500 1.10 christos STB_LOCAL/STT_SECTION symbols specially. The output symbol is 501 1.1 christos going to be the section symbol corresponding to the output 502 1.1 christos section, which means that the addend must be adjusted 503 1.1 christos accordingly. */ 504 1.1 christos 505 1.1 christos static int 506 1.1 christos fr30_elf_relocate_section (bfd *output_bfd, 507 1.1 christos struct bfd_link_info *info, 508 1.1 christos bfd *input_bfd, 509 1.1 christos asection *input_section, 510 1.1 christos bfd_byte *contents, 511 1.1 christos Elf_Internal_Rela *relocs, 512 1.1 christos Elf_Internal_Sym *local_syms, 513 1.1 christos asection **local_sections) 514 1.1 christos { 515 1.1 christos Elf_Internal_Shdr *symtab_hdr; 516 1.1 christos struct elf_link_hash_entry **sym_hashes; 517 1.1 christos Elf_Internal_Rela *rel; 518 1.1 christos Elf_Internal_Rela *relend; 519 1.1 christos 520 1.1 christos symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr; 521 1.1 christos sym_hashes = elf_sym_hashes (input_bfd); 522 1.1 christos relend = relocs + input_section->reloc_count; 523 1.1 christos 524 1.1 christos for (rel = relocs; rel < relend; rel ++) 525 1.1 christos { 526 1.1 christos reloc_howto_type *howto; 527 1.1 christos unsigned long r_symndx; 528 1.1 christos Elf_Internal_Sym *sym; 529 1.1 christos asection *sec; 530 1.1 christos struct elf_link_hash_entry *h; 531 1.1 christos bfd_vma relocation; 532 1.1 christos bfd_reloc_status_type r; 533 1.1 christos const char *name; 534 1.1 christos int r_type; 535 1.1 christos 536 1.1 christos r_type = ELF32_R_TYPE (rel->r_info); 537 1.1 christos 538 1.1 christos if ( r_type == R_FR30_GNU_VTINHERIT 539 1.1 christos || r_type == R_FR30_GNU_VTENTRY) 540 1.1 christos continue; 541 1.1 christos 542 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info); 543 1.1 christos 544 1.1 christos howto = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info); 545 1.1 christos h = NULL; 546 1.1 christos sym = NULL; 547 1.1 christos sec = NULL; 548 1.1 christos 549 1.1 christos if (r_symndx < symtab_hdr->sh_info) 550 1.1 christos { 551 1.1 christos sym = local_syms + r_symndx; 552 1.9 christos sec = local_sections [r_symndx]; 553 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 554 1.1 christos 555 1.1 christos name = bfd_elf_string_from_elf_section 556 1.10 christos (input_bfd, symtab_hdr->sh_link, sym->st_name); 557 1.1 christos name = name == NULL ? bfd_section_name (sec) : name; 558 1.1 christos } 559 1.1 christos else 560 1.1 christos { 561 1.1 christos bool unresolved_reloc, warned, ignored; 562 1.1 christos 563 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 564 1.1 christos r_symndx, symtab_hdr, sym_hashes, 565 1.1 christos h, sec, relocation, 566 1.1 christos unresolved_reloc, warned, ignored); 567 1.1 christos 568 1.1 christos name = h->root.root.string; 569 1.1 christos } 570 1.6 christos 571 1.1 christos if (sec != NULL && discarded_section (sec)) 572 1.1 christos RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, 573 1.1 christos rel, 1, relend, howto, 0, contents); 574 1.1 christos 575 1.1 christos if (bfd_link_relocatable (info)) 576 1.1 christos continue; 577 1.1 christos 578 1.1 christos r = fr30_final_link_relocate (howto, input_bfd, input_section, 579 1.1 christos contents, rel, relocation); 580 1.1 christos 581 1.1 christos if (r != bfd_reloc_ok) 582 1.1 christos { 583 1.6 christos const char * msg = (const char *) NULL; 584 1.1 christos 585 1.1 christos switch (r) 586 1.1 christos { 587 1.1 christos case bfd_reloc_overflow: 588 1.1 christos (*info->callbacks->reloc_overflow) 589 1.6 christos (info, (h ? &h->root : NULL), name, howto->name, 590 1.10 christos (bfd_vma) 0, input_bfd, input_section, rel->r_offset); 591 1.1 christos break; 592 1.1 christos 593 1.1 christos case bfd_reloc_undefined: 594 1.1 christos (*info->callbacks->undefined_symbol) 595 1.1 christos (info, name, input_bfd, input_section, rel->r_offset, true); 596 1.1 christos break; 597 1.1 christos 598 1.1 christos case bfd_reloc_outofrange: 599 1.1 christos msg = _("internal error: out of range error"); 600 1.1 christos break; 601 1.1 christos 602 1.1 christos case bfd_reloc_notsupported: 603 1.1 christos msg = _("internal error: unsupported relocation error"); 604 1.1 christos break; 605 1.1 christos 606 1.1 christos case bfd_reloc_dangerous: 607 1.1 christos msg = _("internal error: dangerous relocation"); 608 1.1 christos break; 609 1.1 christos 610 1.1 christos default: 611 1.6 christos msg = _("internal error: unknown error"); 612 1.6 christos break; 613 1.1 christos } 614 1.1 christos 615 1.1 christos if (msg) 616 1.10 christos (*info->callbacks->warning) (info, msg, name, input_bfd, 617 1.1 christos input_section, rel->r_offset); 618 1.1 christos } 619 1.1 christos } 620 1.1 christos 621 1.1 christos return true; 622 1.1 christos } 623 1.1 christos 624 1.1 christos /* Return the section that should be marked against GC for a given 626 1.1 christos relocation. */ 627 1.1 christos 628 1.1 christos static asection * 629 1.1 christos fr30_elf_gc_mark_hook (asection *sec, 630 1.1 christos struct bfd_link_info *info, 631 1.1 christos Elf_Internal_Rela *rel, 632 1.1 christos struct elf_link_hash_entry *h, 633 1.1 christos Elf_Internal_Sym *sym) 634 1.1 christos { 635 1.1 christos if (h != NULL) 636 1.1 christos switch (ELF32_R_TYPE (rel->r_info)) 637 1.1 christos { 638 1.1 christos case R_FR30_GNU_VTINHERIT: 639 1.1 christos case R_FR30_GNU_VTENTRY: 640 1.1 christos return NULL; 641 1.1 christos } 642 1.1 christos 643 1.1 christos return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 644 1.10 christos } 645 1.1 christos 646 1.1 christos /* Look through the relocs for a section during the first phase. 647 1.1 christos Since we don't do .gots or .plts, we just need to consider the 648 1.1 christos virtual table relocs for gc. */ 649 1.1 christos 650 1.1 christos static bool 651 1.1 christos fr30_elf_check_relocs (bfd *abfd, 652 1.1 christos struct bfd_link_info *info, 653 1.1 christos asection *sec, 654 1.1 christos const Elf_Internal_Rela *relocs) 655 1.6 christos { 656 1.10 christos Elf_Internal_Shdr *symtab_hdr; 657 1.1 christos struct elf_link_hash_entry **sym_hashes; 658 1.1 christos const Elf_Internal_Rela *rel; 659 1.1 christos const Elf_Internal_Rela *rel_end; 660 1.1 christos 661 1.1 christos if (bfd_link_relocatable (info)) 662 1.1 christos return true; 663 1.1 christos 664 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 665 1.1 christos sym_hashes = elf_sym_hashes (abfd); 666 1.1 christos 667 1.1 christos rel_end = relocs + sec->reloc_count; 668 1.1 christos for (rel = relocs; rel < rel_end; rel++) 669 1.8 christos { 670 1.1 christos struct elf_link_hash_entry *h; 671 1.1 christos unsigned long r_symndx; 672 1.1 christos 673 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info); 674 1.1 christos if (r_symndx < symtab_hdr->sh_info) 675 1.1 christos h = NULL; 676 1.1 christos else 677 1.1 christos { 678 1.1 christos h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 679 1.8 christos while (h->root.type == bfd_link_hash_indirect 680 1.8 christos || h->root.type == bfd_link_hash_warning) 681 1.8 christos h = (struct elf_link_hash_entry *) h->root.u.i.link; 682 1.8 christos } 683 1.8 christos 684 1.10 christos switch (ELF32_R_TYPE (rel->r_info)) 685 1.8 christos { 686 1.8 christos /* This relocation describes the C++ object vtable hierarchy. 687 1.8 christos Reconstruct it for later use during GC. */ 688 1.8 christos case R_FR30_GNU_VTINHERIT: 689 1.8 christos if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 690 1.9 christos return false; 691 1.10 christos break; 692 1.8 christos 693 1.8 christos /* This relocation describes which C++ vtable entries are actually 694 1.1 christos used. Record for later use during GC. */ 695 1.1 christos case R_FR30_GNU_VTENTRY: 696 1.10 christos if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 697 1.1 christos return false; 698 1.1 christos break; 699 1.1 christos } 700 1.1 christos } 701 1.1 christos 702 1.1 christos return true; 703 1.1 christos } 704 1.8 christos 705 1.1 christos #define ELF_ARCH bfd_arch_fr30 707 1.1 christos #define ELF_MACHINE_CODE EM_FR30 708 1.1 christos #define ELF_MACHINE_ALT1 EM_CYGNUS_FR30 709 1.1 christos #define ELF_MAXPAGESIZE 0x1000 710 1.1 christos 711 1.8 christos #define TARGET_BIG_SYM fr30_elf32_vec 712 1.1 christos #define TARGET_BIG_NAME "elf32-fr30" 713 1.1 christos 714 1.1 christos #define elf_info_to_howto_rel NULL 715 1.1 christos #define elf_info_to_howto fr30_info_to_howto_rela 716 1.1 christos #define elf_backend_relocate_section fr30_elf_relocate_section 717 1.8 christos #define elf_backend_gc_mark_hook fr30_elf_gc_mark_hook 718 1.1 christos #define elf_backend_check_relocs fr30_elf_check_relocs 719 1.1 christos 720 #define elf_backend_can_gc_sections 1 721 #define elf_backend_rela_normal 1 722 723 #define bfd_elf32_bfd_reloc_type_lookup fr30_reloc_type_lookup 724 #define bfd_elf32_bfd_reloc_name_lookup fr30_reloc_name_lookup 725 726 #include "elf32-target.h" 727