1 1.1 christos /* Visium-specific support for 32-bit ELF. 2 1.1 christos 3 1.9 christos Copyright (C) 2003-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of BFD, the Binary File Descriptor library. 6 1.1 christos 7 1.1 christos This program is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3 of the License, or 10 1.1 christos (at your option) any later version. 11 1.1 christos 12 1.1 christos This program is distributed in the hope that it will be useful, 13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 christos GNU General Public License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this program; if not, write to the Free Software 19 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, 20 1.1 christos Boston, MA 02110-1301, USA. */ 21 1.1 christos 22 1.1 christos #include "sysdep.h" 23 1.1 christos #include "bfd.h" 24 1.1 christos #include "sysdep.h" 25 1.1 christos #include "libbfd.h" 26 1.1 christos #include "elf-bfd.h" 27 1.1 christos #include "elf/visium.h" 28 1.6 christos #include "libiberty.h" 29 1.1 christos 30 1.1 christos static bfd_reloc_status_type visium_elf_howto_parity_reloc 31 1.8 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 32 1.1 christos 33 1.1 christos static reloc_howto_type visium_elf_howto_table[] = { 34 1.1 christos /* This reloc does nothing. */ 35 1.1 christos HOWTO (R_VISIUM_NONE, /* type */ 36 1.1 christos 0, /* rightshift */ 37 1.8 christos 0, /* size */ 38 1.3 christos 0, /* bitsize */ 39 1.8 christos false, /* pc_relative */ 40 1.1 christos 0, /* bitpos */ 41 1.3 christos complain_overflow_dont, /* complain_on_overflow */ 42 1.1 christos bfd_elf_generic_reloc, /* special_function */ 43 1.1 christos "R_VISIUM_NONE", /* name */ 44 1.8 christos false, /* partial_inplace */ 45 1.1 christos 0, /* src_mask */ 46 1.1 christos 0, /* dst_mask */ 47 1.8 christos false), /* pcrel_offset */ 48 1.1 christos 49 1.1 christos /* A 8 bit absolute relocation. */ 50 1.1 christos HOWTO (R_VISIUM_8, /* type */ 51 1.1 christos 0, /* rightshift */ 52 1.8 christos 1, /* size */ 53 1.1 christos 8, /* bitsize */ 54 1.8 christos false, /* pc_relative */ 55 1.1 christos 0, /* bitpos */ 56 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 57 1.1 christos bfd_elf_generic_reloc, /* special_function */ 58 1.1 christos "R_VISIUM_8", /* name */ 59 1.8 christos false, /* partial_inplace */ 60 1.1 christos 0x00, /* src_mask */ 61 1.1 christos 0xff, /* dst_mask */ 62 1.8 christos false), /* pcrel_offset */ 63 1.1 christos 64 1.1 christos /* A 16 bit absolute relocation. */ 65 1.1 christos HOWTO (R_VISIUM_16, /* type */ 66 1.1 christos 0, /* rightshift */ 67 1.8 christos 2, /* size */ 68 1.1 christos 16, /* bitsize */ 69 1.8 christos false, /* pc_relative */ 70 1.1 christos 0, /* bitpos */ 71 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 72 1.1 christos bfd_elf_generic_reloc, /* special_function */ 73 1.1 christos "R_VISIUM_16", /* name */ 74 1.8 christos false, /* partial_inplace */ 75 1.1 christos 0x0000, /* src_mask */ 76 1.1 christos 0xffff, /* dst_mask */ 77 1.8 christos false), /* pcrel_offset */ 78 1.1 christos 79 1.1 christos /* A 32 bit absolute relocation. */ 80 1.1 christos HOWTO (R_VISIUM_32, /* type */ 81 1.1 christos 0, /* rightshift */ 82 1.8 christos 4, /* size */ 83 1.1 christos 32, /* bitsize */ 84 1.8 christos false, /* pc_relative */ 85 1.1 christos 0, /* bitpos */ 86 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 87 1.1 christos bfd_elf_generic_reloc, /* special_function */ 88 1.1 christos "R_VISIUM_32", /* name */ 89 1.8 christos false, /* partial_inplace */ 90 1.1 christos 0x00000000, /* src_mask */ 91 1.1 christos 0xffffffff, /* dst_mask */ 92 1.8 christos false), /* pcrel_offset */ 93 1.1 christos 94 1.1 christos 95 1.1 christos /* A 8 bit PC relative relocation. */ 96 1.1 christos HOWTO (R_VISIUM_8_PCREL, /* type */ 97 1.1 christos 0, /* rightshift */ 98 1.8 christos 1, /* size */ 99 1.1 christos 8, /* bitsize */ 100 1.8 christos true, /* pc_relative */ 101 1.1 christos 0, /* bitpos */ 102 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 103 1.1 christos bfd_elf_generic_reloc, /* special_function */ 104 1.1 christos "R_VISIUM_8_PCREL", /* name */ 105 1.8 christos false, /* partial_inplace */ 106 1.1 christos 0x00, /* src_mask */ 107 1.1 christos 0xff, /* dst_mask */ 108 1.8 christos true), /* pcrel_offset */ 109 1.1 christos 110 1.1 christos /* A 16 bit PC relative relocation. */ 111 1.1 christos HOWTO (R_VISIUM_16_PCREL, /* type */ 112 1.1 christos 0, /* rightshift */ 113 1.8 christos 2, /* size */ 114 1.1 christos 16, /* bitsize */ 115 1.8 christos true, /* pc_relative */ 116 1.1 christos 0, /* bitpos */ 117 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 118 1.1 christos bfd_elf_generic_reloc, /* special_function */ 119 1.1 christos "R_VISIUM_16_PCREL", /* name */ 120 1.8 christos false, /* partial inplace */ 121 1.1 christos 0x0000, /* src_mask */ 122 1.1 christos 0xffff, /* dst_mask */ 123 1.8 christos true), /* pcrel_offset */ 124 1.1 christos 125 1.1 christos /* A 32-bit PC relative relocation. */ 126 1.1 christos HOWTO (R_VISIUM_32_PCREL, /* type */ 127 1.1 christos 0, /* rightshift */ 128 1.8 christos 4, /* size */ 129 1.1 christos 32, /* bitsize */ 130 1.8 christos true, /* pc_relative */ 131 1.1 christos 0, /* bitpos */ 132 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 133 1.1 christos bfd_elf_generic_reloc, /* special_function */ 134 1.1 christos "R_VISIUM_32_PCREL", /* name */ 135 1.8 christos false, /* partial_inplace */ 136 1.1 christos 0, /* src_mask */ 137 1.1 christos 0xffffffff, /* dst_mask */ 138 1.8 christos true), /* pcrel_offset */ 139 1.1 christos 140 1.1 christos /* A 16-bit PC word relative offset, relative to start of instruction 141 1.1 christos and always in the second half of the instruction. */ 142 1.1 christos HOWTO (R_VISIUM_PC16, /* type */ 143 1.1 christos 2, /* rightshift */ 144 1.8 christos 4, /* size */ 145 1.1 christos 16, /* bitsize */ 146 1.8 christos true, /* pc_relative */ 147 1.1 christos 0, /* bitpos */ 148 1.1 christos complain_overflow_signed, /* complain_on_overflow */ 149 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 150 1.1 christos "R_VISIUM_PC16", /* name */ 151 1.8 christos false, /* partial_inplace */ 152 1.1 christos 0x00000000, /* src_mask */ 153 1.1 christos 0x0000ffff, /* dst_mask */ 154 1.8 christos true), /* pcrel_offset */ 155 1.1 christos 156 1.1 christos /* The high 16 bits of symbol value. */ 157 1.1 christos HOWTO (R_VISIUM_HI16, /* type */ 158 1.1 christos 16, /* rightshift */ 159 1.8 christos 4, /* size */ 160 1.1 christos 16, /* bitsize */ 161 1.8 christos false, /* pc_relative */ 162 1.1 christos 0, /* bitpos */ 163 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 164 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 165 1.1 christos "R_VISIUM_HI16", /* name */ 166 1.8 christos false, /* partial_inplace */ 167 1.1 christos 0x00000000, /* src_mask */ 168 1.1 christos 0x0000ffff, /* dst_mask */ 169 1.8 christos false), /* pcrel_offset */ 170 1.1 christos 171 1.1 christos /* The low 16 bits of symbol value. */ 172 1.1 christos HOWTO (R_VISIUM_LO16, /* type */ 173 1.1 christos 0, /* rightshift */ 174 1.8 christos 4, /* size */ 175 1.1 christos 16, /* bitsize */ 176 1.8 christos false, /* pc_relative */ 177 1.1 christos 0, /* bitpos */ 178 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 179 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 180 1.1 christos "R_VISIUM_LO16", /* name */ 181 1.8 christos false, /* partial_inplace */ 182 1.1 christos 0x00000000, /* src_mask */ 183 1.1 christos 0x0000ffff, /* dst_mask */ 184 1.8 christos false), /* pcrel_offset */ 185 1.1 christos 186 1.1 christos /* A 16 bit immediate value. */ 187 1.1 christos HOWTO (R_VISIUM_IM16, /* type */ 188 1.1 christos 0, /* rightshift */ 189 1.8 christos 4, /* size */ 190 1.1 christos 16, /* bitsize */ 191 1.8 christos false, /* pc_relative */ 192 1.1 christos 0, /* bitpos */ 193 1.1 christos complain_overflow_unsigned, /* complain_on_overflow */ 194 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 195 1.1 christos "R_VISIUM_IM16", /* name */ 196 1.8 christos false, /* partial_inplace */ 197 1.1 christos 0x0000000, /* src_mask */ 198 1.1 christos 0x000ffff, /* dst_mask */ 199 1.8 christos false), /* pcrel_offset */ 200 1.1 christos 201 1.1 christos /* The high 16 bits of symbol value, pc relative. */ 202 1.1 christos HOWTO (R_VISIUM_HI16_PCREL, /* type */ 203 1.1 christos 16, /* rightshift */ 204 1.8 christos 4, /* size */ 205 1.1 christos 16, /* bitsize */ 206 1.8 christos true, /* pc_relative */ 207 1.1 christos 0, /* bitpos */ 208 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 209 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 210 1.1 christos "R_VISIUM_HI16_PCREL", /* name */ 211 1.8 christos false, /* partial_inplace */ 212 1.1 christos 0x00000000, /* src_mask */ 213 1.1 christos 0x0000ffff, /* dst_mask */ 214 1.8 christos true), /* pcrel_offset */ 215 1.1 christos 216 1.1 christos /* The low 16 bits of symbol value, pc relative. */ 217 1.1 christos HOWTO (R_VISIUM_LO16_PCREL, /* type */ 218 1.1 christos 0, /* rightshift */ 219 1.8 christos 4, /* size */ 220 1.1 christos 16, /* bitsize */ 221 1.8 christos true, /* pc_relative */ 222 1.1 christos 0, /* bitpos */ 223 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 224 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 225 1.1 christos "R_VISIUM_LO16_PCREL", /* name */ 226 1.8 christos false, /* partial_inplace */ 227 1.1 christos 0x00000000, /* src_mask */ 228 1.1 christos 0x0000ffff, /* dst_mask */ 229 1.8 christos true), /* pcrel_offset */ 230 1.1 christos 231 1.1 christos /* A 16 bit immediate value, pc relative. */ 232 1.1 christos HOWTO (R_VISIUM_IM16_PCREL, /* type */ 233 1.1 christos 0, /* rightshift */ 234 1.8 christos 4, /* size */ 235 1.1 christos 16, /* bitsize */ 236 1.8 christos true, /* pc_relative */ 237 1.1 christos 0, /* bitpos */ 238 1.1 christos complain_overflow_unsigned, /* complain_on_overflow */ 239 1.1 christos visium_elf_howto_parity_reloc, /* special_function */ 240 1.1 christos "R_VISIUM_IM16_PCREL", /* name */ 241 1.8 christos false, /* partial_inplace */ 242 1.1 christos 0x0000000, /* src_mask */ 243 1.1 christos 0x000ffff, /* dst_mask */ 244 1.8 christos true), /* pcrel_offset */ 245 1.1 christos 246 1.1 christos }; 247 1.1 christos 248 1.1 christos /* GNU extension to record C++ vtable hierarchy. */ 249 1.1 christos static reloc_howto_type visium_elf_vtinherit_howto = 250 1.1 christos HOWTO (R_VISIUM_GNU_VTINHERIT, /* type */ 251 1.1 christos 0, /* rightshift */ 252 1.8 christos 4, /* size */ 253 1.1 christos 0, /* bitsize */ 254 1.8 christos false, /* pc_relative */ 255 1.1 christos 0, /* bitpos */ 256 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 257 1.1 christos NULL, /* special_function */ 258 1.1 christos "R_VISIUM_GNU_VTINHERIT", /* name */ 259 1.8 christos false, /* partial_inplace */ 260 1.1 christos 0, /* src_mask */ 261 1.1 christos 0, /* dst_mask */ 262 1.8 christos false); /* pcrel_offset */ 263 1.1 christos 264 1.1 christos /* GNU extension to record C++ vtable member usage. */ 265 1.1 christos static reloc_howto_type visium_elf_vtentry_howto = 266 1.1 christos HOWTO (R_VISIUM_GNU_VTENTRY, /* type */ 267 1.1 christos 0, /* rightshift */ 268 1.8 christos 4, /* size */ 269 1.1 christos 0, /* bitsize */ 270 1.8 christos false, /* pc_relative */ 271 1.1 christos 0, /* bitpos */ 272 1.1 christos complain_overflow_dont, /* complain_on_overflow */ 273 1.1 christos NULL, /* special_function */ 274 1.1 christos "R_VISIUM_GNU_VTENTRY", /* name */ 275 1.8 christos false, /* partial_inplace */ 276 1.1 christos 0, /* src_mask */ 277 1.1 christos 0, /* dst_mask */ 278 1.8 christos false); /* pcrel_offset */ 279 1.1 christos 280 1.1 christos /* Return the parity bit for INSN shifted to its final position. */ 281 1.1 christos 282 1.1 christos static bfd_vma 283 1.1 christos visium_parity_bit (bfd_vma insn) 284 1.1 christos { 285 1.1 christos bfd_vma p = 0; 286 1.1 christos int i; 287 1.1 christos 288 1.1 christos for (i = 0; i < 31; i++) 289 1.1 christos { 290 1.1 christos p ^= (insn & 1); 291 1.1 christos insn >>= 1; 292 1.1 christos } 293 1.1 christos 294 1.1 christos return p << 31; 295 1.1 christos } 296 1.1 christos 297 1.1 christos /* This "special function" will only be used when the input and 298 1.1 christos output files have different formats ie. when generating S-records 299 1.1 christos directly using "--oformat srec". Otherwise we use 300 1.1 christos _bfd_final_link_relocate which uses a howto structure, but does 301 1.1 christos not use the special_function field. 302 1.1 christos 303 1.1 christos It sets instruction parity to even. This cannot be done by a howto. */ 304 1.1 christos 305 1.1 christos static bfd_reloc_status_type 306 1.1 christos visium_elf_howto_parity_reloc (bfd * input_bfd, arelent *reloc_entry, 307 1.8 christos asymbol *symbol, void *data, 308 1.1 christos asection *input_section, bfd *output_bfd, 309 1.1 christos char **error_message ATTRIBUTE_UNUSED) 310 1.1 christos { 311 1.1 christos bfd_reloc_status_type ret; 312 1.1 christos bfd_vma relocation; 313 1.1 christos bfd_byte *inplace_address; 314 1.1 christos bfd_vma insn; 315 1.1 christos 316 1.1 christos /* This part is from bfd_elf_generic_reloc. 317 1.1 christos If we're relocating, and this an external symbol, we don't want 318 1.1 christos to change anything. */ 319 1.1 christos if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0) 320 1.1 christos { 321 1.1 christos reloc_entry->address += input_section->output_offset; 322 1.1 christos return bfd_reloc_ok; 323 1.1 christos } 324 1.1 christos 325 1.1 christos /* Now do the reloc in the usual way. */ 326 1.1 christos 327 1.1 christos /* Sanity check the address (offset in section). */ 328 1.1 christos if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section)) 329 1.1 christos return bfd_reloc_outofrange; 330 1.1 christos 331 1.1 christos ret = bfd_reloc_ok; 332 1.1 christos if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL) 333 1.1 christos ret = bfd_reloc_undefined; 334 1.1 christos 335 1.1 christos if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL) 336 1.1 christos relocation = 0; 337 1.1 christos else 338 1.1 christos relocation = symbol->value; 339 1.1 christos 340 1.1 christos /* Only do this for a final link. */ 341 1.1 christos if (output_bfd == (bfd *) NULL) 342 1.1 christos { 343 1.1 christos relocation += symbol->section->output_section->vma; 344 1.1 christos relocation += symbol->section->output_offset; 345 1.1 christos } 346 1.1 christos 347 1.1 christos relocation += reloc_entry->addend; 348 1.1 christos inplace_address = (bfd_byte *) data + reloc_entry->address; 349 1.1 christos insn = bfd_get_32 (input_bfd, inplace_address); 350 1.1 christos 351 1.1 christos if (reloc_entry->howto->pc_relative) 352 1.1 christos { 353 1.6 christos relocation -= input_section->output_section->vma; 354 1.6 christos relocation -= input_section->output_offset; 355 1.1 christos relocation -= reloc_entry->address; 356 1.1 christos } 357 1.1 christos 358 1.1 christos switch (reloc_entry->howto->type) 359 1.1 christos { 360 1.1 christos case R_VISIUM_PC16: 361 1.6 christos if (ret == bfd_reloc_ok 362 1.6 christos && ((bfd_signed_vma) relocation < -0x20000 363 1.6 christos || (bfd_signed_vma) relocation > 0x1ffff)) 364 1.1 christos ret = bfd_reloc_overflow; 365 1.6 christos relocation = (relocation >> 2) & 0xffff; 366 1.1 christos break; 367 1.1 christos case R_VISIUM_HI16: 368 1.1 christos case R_VISIUM_HI16_PCREL: 369 1.1 christos relocation = (relocation >> 16) & 0xffff; 370 1.1 christos break; 371 1.1 christos case R_VISIUM_LO16: 372 1.1 christos case R_VISIUM_LO16_PCREL: 373 1.1 christos relocation &= 0xffff; 374 1.1 christos break; 375 1.1 christos case R_VISIUM_IM16: 376 1.1 christos case R_VISIUM_IM16_PCREL: 377 1.1 christos if (ret == bfd_reloc_ok && (relocation & 0xffff0000) != 0) 378 1.1 christos ret = bfd_reloc_overflow; 379 1.1 christos relocation &= 0xffff; 380 1.1 christos break; 381 1.1 christos } 382 1.1 christos insn = (insn & 0x7fff0000) | relocation; 383 1.1 christos insn |= visium_parity_bit (insn); 384 1.1 christos bfd_put_32 (input_bfd, insn, inplace_address); 385 1.1 christos 386 1.1 christos if (output_bfd != (bfd *) NULL) 387 1.1 christos reloc_entry->address += input_section->output_offset; 388 1.1 christos 389 1.1 christos return ret; 390 1.1 christos } 391 1.1 christos 392 1.1 christos static reloc_howto_type * 393 1.1 christos visium_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 394 1.1 christos bfd_reloc_code_real_type code) 395 1.1 christos { 396 1.1 christos /* Note that the visium_elf_howto_table is indexed by the R_ 397 1.1 christos constants. Thus, the order that the howto records appear in the 398 1.1 christos table *must* match the order of the relocation types defined in 399 1.1 christos include/elf/visium.h. */ 400 1.1 christos switch (code) 401 1.1 christos { 402 1.1 christos case BFD_RELOC_NONE: 403 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_NONE]; 404 1.1 christos case BFD_RELOC_8: 405 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_8]; 406 1.1 christos case BFD_RELOC_16: 407 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_16]; 408 1.1 christos case BFD_RELOC_32: 409 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_32]; 410 1.1 christos case BFD_RELOC_8_PCREL: 411 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_8_PCREL]; 412 1.1 christos case BFD_RELOC_16_PCREL: 413 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_16_PCREL]; 414 1.1 christos case BFD_RELOC_32_PCREL: 415 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_32_PCREL]; 416 1.1 christos case BFD_RELOC_VISIUM_REL16: 417 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_PC16]; 418 1.1 christos case BFD_RELOC_VISIUM_HI16: 419 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_HI16]; 420 1.1 christos case BFD_RELOC_VISIUM_LO16: 421 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_LO16]; 422 1.1 christos case BFD_RELOC_VISIUM_IM16: 423 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_IM16]; 424 1.1 christos case BFD_RELOC_VISIUM_HI16_PCREL: 425 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_HI16_PCREL]; 426 1.1 christos case BFD_RELOC_VISIUM_LO16_PCREL: 427 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_LO16_PCREL]; 428 1.1 christos case BFD_RELOC_VISIUM_IM16_PCREL: 429 1.1 christos return &visium_elf_howto_table[(int) R_VISIUM_IM16_PCREL]; 430 1.1 christos case BFD_RELOC_VTABLE_INHERIT: 431 1.1 christos return &visium_elf_vtinherit_howto; 432 1.1 christos case BFD_RELOC_VTABLE_ENTRY: 433 1.1 christos return &visium_elf_vtentry_howto; 434 1.1 christos default: 435 1.1 christos return NULL; 436 1.1 christos } 437 1.1 christos } 438 1.1 christos 439 1.1 christos static reloc_howto_type * 440 1.1 christos visium_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name) 441 1.1 christos { 442 1.1 christos unsigned int i; 443 1.1 christos 444 1.1 christos for (i = 0; 445 1.1 christos i < (sizeof (visium_elf_howto_table) 446 1.1 christos / sizeof (visium_elf_howto_table[0])); i++) 447 1.1 christos if (visium_elf_howto_table[i].name != NULL 448 1.1 christos && strcasecmp (visium_elf_howto_table[i].name, r_name) == 0) 449 1.1 christos return &visium_elf_howto_table[i]; 450 1.1 christos 451 1.1 christos if (strcasecmp (visium_elf_vtinherit_howto.name, r_name) == 0) 452 1.1 christos return &visium_elf_vtinherit_howto; 453 1.1 christos if (strcasecmp (visium_elf_vtentry_howto.name, r_name) == 0) 454 1.1 christos return &visium_elf_vtentry_howto; 455 1.1 christos 456 1.1 christos return NULL; 457 1.1 christos } 458 1.1 christos 459 1.1 christos /* Set the howto pointer for a VISIUM ELF reloc. */ 460 1.1 christos 461 1.8 christos static bool 462 1.6 christos visium_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, 463 1.1 christos Elf_Internal_Rela *dst) 464 1.1 christos { 465 1.1 christos unsigned int r_type = ELF32_R_TYPE (dst->r_info); 466 1.1 christos 467 1.1 christos switch (r_type) 468 1.1 christos { 469 1.1 christos case R_VISIUM_GNU_VTINHERIT: 470 1.1 christos cache_ptr->howto = &visium_elf_vtinherit_howto; 471 1.1 christos break; 472 1.1 christos 473 1.1 christos case R_VISIUM_GNU_VTENTRY: 474 1.1 christos cache_ptr->howto = &visium_elf_vtentry_howto; 475 1.1 christos break; 476 1.1 christos 477 1.1 christos default: 478 1.6 christos if (r_type >= ARRAY_SIZE (visium_elf_howto_table)) 479 1.1 christos { 480 1.5 christos /* xgettext:c-format */ 481 1.6 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"), 482 1.6 christos abfd, r_type); 483 1.6 christos bfd_set_error (bfd_error_bad_value); 484 1.8 christos return false; 485 1.1 christos } 486 1.1 christos cache_ptr->howto = &visium_elf_howto_table[r_type]; 487 1.1 christos break; 488 1.1 christos } 489 1.8 christos return true; 490 1.1 christos } 491 1.1 christos 492 1.1 christos /* Look through the relocs for a section during the first phase. 493 1.1 christos Since we don't do .gots or .plts, we just need to consider the 494 1.1 christos virtual table relocs for gc. */ 495 1.1 christos 496 1.8 christos static bool 497 1.1 christos visium_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 498 1.1 christos asection *sec, const Elf_Internal_Rela *relocs) 499 1.1 christos { 500 1.1 christos Elf_Internal_Shdr *symtab_hdr; 501 1.1 christos struct elf_link_hash_entry **sym_hashes; 502 1.1 christos const Elf_Internal_Rela *rel; 503 1.1 christos const Elf_Internal_Rela *rel_end; 504 1.1 christos 505 1.4 christos if (bfd_link_relocatable (info)) 506 1.8 christos return true; 507 1.1 christos 508 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 509 1.1 christos sym_hashes = elf_sym_hashes (abfd); 510 1.1 christos 511 1.1 christos rel_end = relocs + sec->reloc_count; 512 1.1 christos for (rel = relocs; rel < rel_end; rel++) 513 1.1 christos { 514 1.1 christos struct elf_link_hash_entry *h; 515 1.1 christos unsigned long r_symndx; 516 1.1 christos 517 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info); 518 1.1 christos if (r_symndx < symtab_hdr->sh_info) 519 1.1 christos h = NULL; 520 1.1 christos else 521 1.1 christos { 522 1.1 christos h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 523 1.1 christos while (h->root.type == bfd_link_hash_indirect 524 1.1 christos || h->root.type == bfd_link_hash_warning) 525 1.1 christos h = (struct elf_link_hash_entry *) h->root.u.i.link; 526 1.1 christos } 527 1.1 christos 528 1.1 christos switch (ELF32_R_TYPE (rel->r_info)) 529 1.1 christos { 530 1.1 christos /* This relocation describes the C++ object vtable hierarchy. 531 1.1 christos Reconstruct it for later use during GC. */ 532 1.1 christos case R_VISIUM_GNU_VTINHERIT: 533 1.1 christos if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 534 1.8 christos return false; 535 1.1 christos break; 536 1.1 christos 537 1.1 christos /* This relocation describes which C++ vtable entries are actually 538 1.1 christos used. Record for later use during GC. */ 539 1.1 christos case R_VISIUM_GNU_VTENTRY: 540 1.1 christos if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 541 1.8 christos return false; 542 1.1 christos break; 543 1.1 christos } 544 1.1 christos } 545 1.1 christos 546 1.8 christos return true; 547 1.1 christos } 548 1.1 christos 549 1.1 christos /* Relocate a VISIUM ELF section. */ 550 1.1 christos 551 1.8 christos static int 552 1.1 christos visium_elf_relocate_section (bfd *output_bfd, 553 1.1 christos struct bfd_link_info *info, bfd *input_bfd, 554 1.1 christos asection *input_section, bfd_byte *contents, 555 1.1 christos Elf_Internal_Rela *relocs, 556 1.1 christos Elf_Internal_Sym *local_syms, 557 1.1 christos asection **local_sections) 558 1.1 christos { 559 1.1 christos Elf_Internal_Shdr *symtab_hdr; 560 1.1 christos struct elf_link_hash_entry **sym_hashes; 561 1.1 christos Elf_Internal_Rela *rel; 562 1.1 christos Elf_Internal_Rela *relend; 563 1.1 christos 564 1.1 christos symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 565 1.1 christos sym_hashes = elf_sym_hashes (input_bfd); 566 1.1 christos relend = relocs + input_section->reloc_count; 567 1.1 christos 568 1.1 christos for (rel = relocs; rel < relend; rel++) 569 1.1 christos { 570 1.1 christos reloc_howto_type *howto; 571 1.1 christos unsigned long r_symndx; 572 1.1 christos Elf_Internal_Sym *sym; 573 1.1 christos asection *sec; 574 1.1 christos struct elf_link_hash_entry *h; 575 1.1 christos bfd_vma relocation; 576 1.1 christos bfd_reloc_status_type r; 577 1.1 christos const char *name = NULL; 578 1.1 christos int r_type; 579 1.1 christos bfd_vma insn; 580 1.1 christos 581 1.1 christos r_type = ELF32_R_TYPE (rel->r_info); 582 1.1 christos 583 1.1 christos if (r_type == R_VISIUM_GNU_VTINHERIT || r_type == R_VISIUM_GNU_VTENTRY) 584 1.1 christos continue; 585 1.1 christos 586 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info); 587 1.1 christos 588 1.1 christos howto = visium_elf_howto_table + ELF32_R_TYPE (rel->r_info); 589 1.1 christos h = NULL; 590 1.1 christos sym = NULL; 591 1.1 christos sec = NULL; 592 1.1 christos 593 1.1 christos if (r_symndx < symtab_hdr->sh_info) 594 1.1 christos { 595 1.1 christos /* This is a local symbol. */ 596 1.1 christos sym = local_syms + r_symndx; 597 1.1 christos sec = local_sections[r_symndx]; 598 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 599 1.1 christos 600 1.1 christos name = bfd_elf_string_from_elf_section 601 1.1 christos (input_bfd, symtab_hdr->sh_link, sym->st_name); 602 1.7 christos name = name == NULL ? bfd_section_name (sec) : name; 603 1.1 christos } 604 1.1 christos else 605 1.1 christos { 606 1.8 christos bool unresolved_reloc; 607 1.8 christos bool warned, ignored; 608 1.1 christos 609 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 610 1.1 christos r_symndx, symtab_hdr, sym_hashes, 611 1.1 christos h, sec, relocation, 612 1.1 christos unresolved_reloc, warned, ignored); 613 1.1 christos 614 1.1 christos name = h->root.root.string; 615 1.1 christos } 616 1.1 christos 617 1.1 christos if (sec != NULL && discarded_section (sec)) 618 1.1 christos { 619 1.1 christos /* For relocs against symbols from removed linkonce sections, 620 1.1 christos or sections discarded by a linker script, we just want the 621 1.1 christos section contents zeroed. Avoid any special processing. */ 622 1.1 christos _bfd_clear_contents (howto, input_bfd, input_section, 623 1.6 christos contents, rel->r_offset); 624 1.1 christos 625 1.1 christos rel->r_info = 0; 626 1.1 christos rel->r_addend = 0; 627 1.1 christos continue; 628 1.1 christos } 629 1.1 christos 630 1.4 christos if (bfd_link_relocatable (info)) 631 1.1 christos continue; 632 1.1 christos 633 1.1 christos switch (r_type) 634 1.1 christos { 635 1.1 christos case R_VISIUM_PC16: 636 1.1 christos case R_VISIUM_HI16: 637 1.1 christos case R_VISIUM_LO16: 638 1.1 christos case R_VISIUM_IM16: 639 1.1 christos case R_VISIUM_HI16_PCREL: 640 1.1 christos case R_VISIUM_LO16_PCREL: 641 1.1 christos case R_VISIUM_IM16_PCREL: 642 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd, input_section, 643 1.1 christos contents, rel->r_offset, 644 1.1 christos relocation, rel->r_addend); 645 1.1 christos 646 1.1 christos /* For instruction relocations, the parity needs correcting. */ 647 1.1 christos if (r == bfd_reloc_ok) 648 1.1 christos { 649 1.1 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset); 650 1.1 christos insn = (insn & 0x7fffffff) | visium_parity_bit (insn); 651 1.1 christos bfd_put_32 (input_bfd, insn, contents + rel->r_offset); 652 1.1 christos } 653 1.1 christos break; 654 1.1 christos 655 1.1 christos default: 656 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd, input_section, 657 1.1 christos contents, rel->r_offset, 658 1.1 christos relocation, rel->r_addend); 659 1.1 christos break; 660 1.1 christos } 661 1.1 christos 662 1.1 christos if (r != bfd_reloc_ok) 663 1.1 christos { 664 1.1 christos const char *msg = (const char *) NULL; 665 1.1 christos 666 1.1 christos switch (r) 667 1.1 christos { 668 1.1 christos case bfd_reloc_overflow: 669 1.4 christos (*info->callbacks->reloc_overflow) 670 1.1 christos (info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0, 671 1.1 christos input_bfd, input_section, rel->r_offset); 672 1.1 christos break; 673 1.1 christos 674 1.1 christos case bfd_reloc_undefined: 675 1.4 christos (*info->callbacks->undefined_symbol) 676 1.8 christos (info, name, input_bfd, input_section, rel->r_offset, true); 677 1.1 christos break; 678 1.1 christos 679 1.1 christos case bfd_reloc_outofrange: 680 1.1 christos msg = _("internal error: out of range error"); 681 1.1 christos break; 682 1.1 christos 683 1.1 christos case bfd_reloc_notsupported: 684 1.1 christos msg = _("internal error: unsupported relocation error"); 685 1.1 christos break; 686 1.1 christos 687 1.1 christos case bfd_reloc_dangerous: 688 1.1 christos msg = _("internal error: dangerous relocation"); 689 1.1 christos break; 690 1.1 christos 691 1.1 christos default: 692 1.1 christos msg = _("internal error: unknown error"); 693 1.1 christos break; 694 1.1 christos } 695 1.1 christos 696 1.1 christos if (msg) 697 1.4 christos (*info->callbacks->warning) (info, msg, name, input_bfd, 698 1.4 christos input_section, rel->r_offset); 699 1.1 christos } 700 1.1 christos } 701 1.1 christos 702 1.8 christos return true; 703 1.1 christos } 704 1.1 christos 705 1.1 christos /* This function is called during section gc to discover the section a 706 1.1 christos to which a particular relocation refers. Return the section that 707 1.1 christos should be marked against GC for a given relocation. */ 708 1.1 christos 709 1.1 christos static asection * 710 1.1 christos visium_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info, 711 1.1 christos Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, 712 1.1 christos Elf_Internal_Sym *sym) 713 1.1 christos { 714 1.1 christos if (h != NULL) 715 1.1 christos switch (ELF32_R_TYPE (rel->r_info)) 716 1.1 christos { 717 1.1 christos case R_VISIUM_GNU_VTINHERIT: 718 1.1 christos case R_VISIUM_GNU_VTENTRY: 719 1.1 christos return NULL; 720 1.1 christos } 721 1.1 christos 722 1.1 christos return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 723 1.1 christos } 724 1.1 christos 725 1.8 christos static bool 726 1.7 christos visium_elf_init_file_header (bfd *abfd, struct bfd_link_info *info) 727 1.1 christos { 728 1.7 christos Elf_Internal_Ehdr *i_ehdrp; 729 1.7 christos 730 1.7 christos if (!_bfd_elf_init_file_header (abfd, info)) 731 1.8 christos return false; 732 1.7 christos 733 1.7 christos i_ehdrp = elf_elfheader (abfd); 734 1.1 christos i_ehdrp->e_ident[EI_ABIVERSION] = 1; 735 1.8 christos return true; 736 1.1 christos } 737 1.1 christos 738 1.1 christos /* Function to set the ELF flag bits. */ 739 1.1 christos 740 1.8 christos static bool 741 1.1 christos visium_elf_set_private_flags (bfd *abfd, flagword flags) 742 1.1 christos { 743 1.1 christos elf_elfheader (abfd)->e_flags = flags; 744 1.8 christos elf_flags_init (abfd) = true; 745 1.8 christos return true; 746 1.1 christos } 747 1.1 christos 748 1.1 christos /* Copy backend specific data from one object module to another. */ 749 1.1 christos 750 1.8 christos static bool 751 1.1 christos visium_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) 752 1.1 christos { 753 1.1 christos if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour 754 1.1 christos || bfd_get_flavour (obfd) != bfd_target_elf_flavour) 755 1.8 christos return true; 756 1.1 christos 757 1.1 christos BFD_ASSERT (!elf_flags_init (obfd) 758 1.1 christos || elf_elfheader (obfd)->e_flags == 759 1.1 christos elf_elfheader (ibfd)->e_flags); 760 1.1 christos 761 1.1 christos elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; 762 1.8 christos elf_flags_init (obfd) = true; 763 1.1 christos 764 1.1 christos /* Copy object attributes. */ 765 1.1 christos _bfd_elf_copy_obj_attributes (ibfd, obfd); 766 1.1 christos 767 1.8 christos return true; 768 1.1 christos } 769 1.1 christos 770 1.1 christos /* Merge backend specific data from an object 771 1.1 christos file to the output object file when linking. */ 772 1.1 christos 773 1.8 christos static bool 774 1.5 christos visium_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) 775 1.1 christos { 776 1.5 christos bfd *obfd = info->output_bfd; 777 1.1 christos flagword old_flags; 778 1.1 christos flagword new_flags; 779 1.1 christos flagword mismatch; 780 1.1 christos const char *opt_arch = NULL; 781 1.1 christos const char *new_opt_with = NULL; 782 1.1 christos const char *old_opt_with = NULL; 783 1.1 christos const char *with = "with"; 784 1.1 christos const char *without = "without"; 785 1.1 christos const char *mcm = "mcm"; 786 1.1 christos const char *mcm24 = "mcm24"; 787 1.1 christos const char *gr6 = "gr6"; 788 1.1 christos 789 1.1 christos new_flags = elf_elfheader (ibfd)->e_flags; 790 1.1 christos old_flags = elf_elfheader (obfd)->e_flags; 791 1.1 christos 792 1.1 christos if (!elf_flags_init (obfd)) 793 1.1 christos { 794 1.1 christos /* First call, no flags set. */ 795 1.8 christos elf_flags_init (obfd) = true; 796 1.1 christos elf_elfheader (obfd)->e_flags = new_flags; 797 1.1 christos } 798 1.1 christos else 799 1.1 christos { 800 1.1 christos mismatch = (new_flags ^ old_flags) 801 1.1 christos & (EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_MCM24 | EF_VISIUM_ARCH_GR6); 802 1.1 christos if (mismatch & EF_VISIUM_ARCH_GR6) 803 1.1 christos { 804 1.1 christos opt_arch = gr6; 805 1.1 christos new_opt_with = new_flags & EF_VISIUM_ARCH_GR6 ? with : without; 806 1.1 christos old_opt_with = old_flags & EF_VISIUM_ARCH_GR6 ? with : without; 807 1.1 christos } 808 1.1 christos else if (mismatch & EF_VISIUM_ARCH_MCM) 809 1.1 christos { 810 1.1 christos opt_arch = mcm; 811 1.1 christos new_opt_with = new_flags & EF_VISIUM_ARCH_MCM ? with : without; 812 1.1 christos old_opt_with = old_flags & EF_VISIUM_ARCH_MCM ? with : without; 813 1.1 christos } 814 1.1 christos else if (mismatch & EF_VISIUM_ARCH_MCM24) 815 1.1 christos { 816 1.1 christos opt_arch = mcm24; 817 1.1 christos new_opt_with = new_flags & EF_VISIUM_ARCH_MCM24 ? with : without; 818 1.1 christos old_opt_with = old_flags & EF_VISIUM_ARCH_MCM24 ? with : without; 819 1.1 christos } 820 1.1 christos 821 1.1 christos if (mismatch) 822 1.1 christos _bfd_error_handler 823 1.5 christos /* xgettext:c-format */ 824 1.6 christos (_("%pB: compiled %s -mtune=%s and linked with modules" 825 1.5 christos " compiled %s -mtune=%s"), 826 1.5 christos ibfd, new_opt_with, opt_arch, old_opt_with, opt_arch); 827 1.1 christos } 828 1.1 christos 829 1.8 christos return true; 830 1.1 christos } 831 1.1 christos 832 1.8 christos static bool 833 1.1 christos visium_elf_print_private_bfd_data (bfd *abfd, void *ptr) 834 1.1 christos { 835 1.1 christos FILE *file = (FILE *) ptr; 836 1.1 christos flagword flags; 837 1.1 christos 838 1.1 christos BFD_ASSERT (abfd != NULL && ptr != NULL); 839 1.1 christos 840 1.1 christos /* Print normal ELF private data. */ 841 1.1 christos _bfd_elf_print_private_bfd_data (abfd, ptr); 842 1.1 christos 843 1.1 christos flags = elf_elfheader (abfd)->e_flags; 844 1.1 christos fprintf (file, _("private flags = 0x%lx:"), (long) flags); 845 1.1 christos 846 1.1 christos if (flags & EF_VISIUM_ARCH_GR6) 847 1.1 christos fprintf (file, " -mtune=gr6"); 848 1.1 christos else if (flags & EF_VISIUM_ARCH_MCM) 849 1.1 christos fprintf (file, " -mtune=mcm"); 850 1.1 christos else if (flags & EF_VISIUM_ARCH_MCM24) 851 1.1 christos fprintf (file, " -mtune=mcm24"); 852 1.1 christos 853 1.1 christos fputc ('\n', file); 854 1.8 christos return true; 855 1.1 christos } 856 1.1 christos 857 1.1 christos #define ELF_ARCH bfd_arch_visium 858 1.1 christos #define ELF_MACHINE_CODE EM_VISIUM 859 1.7 christos #define ELF_OSABI ELFOSABI_STANDALONE 860 1.1 christos #define ELF_MAXPAGESIZE 1 861 1.1 christos 862 1.1 christos #define TARGET_BIG_SYM visium_elf32_vec 863 1.1 christos #define TARGET_BIG_NAME "elf32-visium" 864 1.1 christos 865 1.1 christos #define elf_info_to_howto_rel NULL 866 1.1 christos #define elf_info_to_howto visium_info_to_howto_rela 867 1.1 christos #define elf_backend_relocate_section visium_elf_relocate_section 868 1.1 christos #define elf_backend_gc_mark_hook visium_elf_gc_mark_hook 869 1.1 christos #define elf_backend_check_relocs visium_elf_check_relocs 870 1.1 christos #define elf_backend_rela_normal 1 871 1.1 christos 872 1.1 christos #define elf_backend_can_gc_sections 1 873 1.1 christos 874 1.1 christos #define bfd_elf32_bfd_reloc_type_lookup visium_reloc_type_lookup 875 1.1 christos #define bfd_elf32_bfd_reloc_name_lookup visium_reloc_name_lookup 876 1.1 christos 877 1.1 christos #define bfd_elf32_bfd_set_private_flags visium_elf_set_private_flags 878 1.1 christos #define bfd_elf32_bfd_copy_private_bfd_data visium_elf_copy_private_bfd_data 879 1.1 christos #define bfd_elf32_bfd_merge_private_bfd_data visium_elf_merge_private_bfd_data 880 1.1 christos #define bfd_elf32_bfd_print_private_bfd_data visium_elf_print_private_bfd_data 881 1.7 christos #define elf_backend_init_file_header visium_elf_init_file_header 882 1.1 christos 883 1.1 christos #include "elf32-target.h" 884