1 1.1 christos /* 32-bit ELF support for TI PRU. 2 1.1.1.7 christos Copyright (C) 2014-2026 Free Software Foundation, Inc. 3 1.1 christos Contributed by Dimitar Dimitrov <dimitar (at) dinux.eu> 4 1.1 christos Based on elf32-nios2.c 5 1.1 christos 6 1.1 christos This file is part of BFD, the Binary File Descriptor library. 7 1.1 christos 8 1.1 christos This program is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3 of the License, or 11 1.1 christos (at your option) any later version. 12 1.1 christos 13 1.1 christos This program is distributed in the hope that it will be useful, 14 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of 15 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 1.1 christos GNU General Public License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program; if not, write to the Free Software 20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 1.1 christos MA 02110-1301, USA. */ 22 1.1 christos 23 1.1 christos /* This file handles TI PRU ELF targets. */ 24 1.1 christos 25 1.1 christos #include "sysdep.h" 26 1.1 christos #include "bfd.h" 27 1.1 christos #include "libbfd.h" 28 1.1 christos #include "bfdlink.h" 29 1.1 christos #include "genlink.h" 30 1.1 christos #include "elf-bfd.h" 31 1.1 christos #include "elf/pru.h" 32 1.1 christos #include "opcode/pru.h" 33 1.1.1.2 christos #include "libiberty.h" 34 1.1 christos 35 1.1.1.3 christos /* All users of this file have bfd_octets_per_byte (abfd, sec) == 1. */ 36 1.1.1.3 christos #define OCTETS_PER_BYTE(ABFD, SEC) 1 37 1.1.1.3 christos 38 1.1 christos #define SWAP_VALS(A,B) \ 39 1.1 christos do { \ 40 1.1 christos (A) ^= (B); \ 41 1.1 christos (B) ^= (A); \ 42 1.1 christos (A) ^= (B); \ 43 1.1 christos } while (0) 44 1.1 christos 45 1.1 christos /* Enable debugging printout at stdout with this variable. */ 46 1.1.1.4 christos static bool debug_relax = false; 47 1.1 christos 48 1.1 christos /* Forward declarations. */ 49 1.1 christos static bfd_reloc_status_type pru_elf32_pmem_relocate 50 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 51 1.1 christos static bfd_reloc_status_type pru_elf32_s10_pcrel_relocate 52 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 53 1.1 christos static bfd_reloc_status_type pru_elf32_u8_pcrel_relocate 54 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 55 1.1 christos static bfd_reloc_status_type pru_elf32_ldi32_relocate 56 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 57 1.1 christos static bfd_reloc_status_type bfd_elf_pru_diff_relocate 58 1.1 christos (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 59 1.1 christos 60 1.1 christos /* Target vector. */ 61 1.1 christos extern const bfd_target pru_elf32_vec; 62 1.1 christos 63 1.1 christos /* The relocation table used for SHT_REL sections. */ 64 1.1 christos static reloc_howto_type elf_pru_howto_table_rel[] = { 65 1.1 christos /* No relocation. */ 66 1.1 christos HOWTO (R_PRU_NONE, /* type */ 67 1.1 christos 0, /* rightshift */ 68 1.1.1.4 christos 0, /* size */ 69 1.1.1.4 christos 0, /* bitsize */ 70 1.1.1.4 christos false, /* pc_relative */ 71 1.1 christos 0, /* bitpos */ 72 1.1 christos complain_overflow_dont,/* complain_on_overflow */ 73 1.1 christos bfd_elf_generic_reloc, /* special_function */ 74 1.1 christos "R_PRU_NONE", /* name */ 75 1.1.1.4 christos false, /* partial_inplace */ 76 1.1 christos 0, /* src_mask */ 77 1.1 christos 0, /* dst_mask */ 78 1.1.1.4 christos false), /* pcrel_offset */ 79 1.1 christos 80 1.1 christos HOWTO (R_PRU_16_PMEM, 81 1.1 christos 2, 82 1.1.1.4 christos 2, /* short */ 83 1.1 christos 32, 84 1.1.1.4 christos false, 85 1.1 christos 0, 86 1.1 christos complain_overflow_dont, 87 1.1 christos bfd_elf_generic_reloc, 88 1.1 christos "R_PRU_16_PMEM", 89 1.1.1.4 christos false, 90 1.1 christos 0, /* src_mask */ 91 1.1 christos 0xffff, 92 1.1.1.4 christos false), 93 1.1 christos 94 1.1 christos HOWTO (R_PRU_U16_PMEMIMM, 95 1.1 christos 2, 96 1.1.1.4 christos 4, 97 1.1 christos 32, 98 1.1.1.4 christos false, 99 1.1 christos 8, 100 1.1 christos complain_overflow_unsigned, 101 1.1 christos pru_elf32_pmem_relocate, 102 1.1 christos "R_PRU_U16_PMEMIMM", 103 1.1.1.4 christos false, 104 1.1 christos 0, /* src_mask */ 105 1.1 christos 0x00ffff00, 106 1.1.1.4 christos false), 107 1.1 christos 108 1.1 christos HOWTO (R_PRU_BFD_RELOC_16, 109 1.1 christos 0, 110 1.1.1.4 christos 2, /* short */ 111 1.1 christos 16, 112 1.1.1.4 christos false, 113 1.1 christos 0, 114 1.1 christos complain_overflow_bitfield, 115 1.1 christos bfd_elf_generic_reloc, 116 1.1 christos "R_PRU_BFD_RELOC16", 117 1.1.1.4 christos false, 118 1.1 christos 0, /* src_mask */ 119 1.1 christos 0x0000ffff, 120 1.1.1.4 christos false), 121 1.1 christos 122 1.1 christos /* 16-bit unsigned immediate relocation. */ 123 1.1 christos HOWTO (R_PRU_U16, /* type */ 124 1.1 christos 0, /* rightshift */ 125 1.1.1.4 christos 4, /* size */ 126 1.1 christos 16, /* bitsize */ 127 1.1.1.4 christos false, /* pc_relative */ 128 1.1 christos 8, /* bitpos */ 129 1.1 christos complain_overflow_unsigned, /* complain on overflow */ 130 1.1 christos bfd_elf_generic_reloc, /* special function */ 131 1.1 christos "R_PRU_U16", /* name */ 132 1.1.1.4 christos false, /* partial_inplace */ 133 1.1 christos 0, /* src_mask */ 134 1.1 christos 0x00ffff00, /* dest_mask */ 135 1.1.1.4 christos false), /* pcrel_offset */ 136 1.1 christos 137 1.1 christos HOWTO (R_PRU_32_PMEM, 138 1.1 christos 2, 139 1.1.1.4 christos 4, /* long */ 140 1.1 christos 32, 141 1.1.1.4 christos false, 142 1.1 christos 0, 143 1.1 christos complain_overflow_dont, 144 1.1 christos pru_elf32_pmem_relocate, 145 1.1 christos "R_PRU_32_PMEM", 146 1.1.1.4 christos false, 147 1.1 christos 0, /* src_mask */ 148 1.1 christos 0xffffffff, 149 1.1.1.4 christos false), 150 1.1 christos 151 1.1 christos HOWTO (R_PRU_BFD_RELOC_32, 152 1.1 christos 0, 153 1.1.1.4 christos 4, /* long */ 154 1.1 christos 32, 155 1.1.1.4 christos false, 156 1.1 christos 0, 157 1.1 christos complain_overflow_dont, 158 1.1 christos bfd_elf_generic_reloc, 159 1.1 christos "R_PRU_BFD_RELOC32", 160 1.1.1.4 christos false, 161 1.1 christos 0, /* src_mask */ 162 1.1 christos 0xffffffff, 163 1.1.1.4 christos false), 164 1.1 christos 165 1.1 christos HOWTO (R_PRU_S10_PCREL, 166 1.1 christos 2, 167 1.1.1.4 christos 4, 168 1.1 christos 10, 169 1.1.1.4 christos true, 170 1.1 christos 0, 171 1.1 christos complain_overflow_bitfield, 172 1.1 christos pru_elf32_s10_pcrel_relocate, 173 1.1 christos "R_PRU_S10_PCREL", 174 1.1.1.4 christos false, 175 1.1 christos 0, /* src_mask */ 176 1.1 christos 0x060000ff, 177 1.1.1.4 christos true), 178 1.1 christos 179 1.1 christos HOWTO (R_PRU_U8_PCREL, 180 1.1 christos 2, 181 1.1.1.4 christos 4, 182 1.1 christos 8, 183 1.1.1.4 christos true, 184 1.1 christos 0, 185 1.1 christos complain_overflow_unsigned, 186 1.1 christos pru_elf32_u8_pcrel_relocate, 187 1.1 christos "R_PRU_U8_PCREL", 188 1.1.1.4 christos false, 189 1.1 christos 0, /* src_mask */ 190 1.1 christos 0x000000ff, 191 1.1.1.4 christos true), 192 1.1 christos 193 1.1 christos HOWTO (R_PRU_LDI32, 194 1.1 christos 0, /* rightshift */ 195 1.1.1.4 christos 8, /* size */ 196 1.1 christos 32, /* bitsize */ 197 1.1.1.4 christos false, /* pc_relative */ 198 1.1 christos 0, /* bitpos */ 199 1.1 christos complain_overflow_unsigned, /* complain on overflow */ 200 1.1 christos pru_elf32_ldi32_relocate, /* special function */ 201 1.1 christos "R_PRU_LDI32", /* name */ 202 1.1.1.4 christos false, /* partial_inplace */ 203 1.1 christos 0, /* src_mask */ 204 1.1 christos 0xffffffff, /* dest_mask */ 205 1.1.1.4 christos false), /* pcrel_offset */ 206 1.1 christos 207 1.1 christos /* GNU-specific relocations. */ 208 1.1 christos HOWTO (R_PRU_GNU_BFD_RELOC_8, 209 1.1 christos 0, 210 1.1.1.4 christos 1, /* byte */ 211 1.1 christos 8, 212 1.1.1.4 christos false, 213 1.1 christos 0, 214 1.1 christos complain_overflow_bitfield, 215 1.1 christos bfd_elf_generic_reloc, 216 1.1 christos "R_PRU_BFD_RELOC8", 217 1.1.1.4 christos false, 218 1.1 christos 0, /* src_mask */ 219 1.1 christos 0x000000ff, 220 1.1.1.4 christos false), 221 1.1 christos 222 1.1 christos HOWTO (R_PRU_GNU_DIFF8, /* type */ 223 1.1 christos 0, /* rightshift */ 224 1.1.1.4 christos 1, /* size */ 225 1.1 christos 8, /* bitsize */ 226 1.1.1.4 christos false, /* pc_relative */ 227 1.1 christos 0, /* bitpos */ 228 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 229 1.1 christos bfd_elf_pru_diff_relocate, /* special_function */ 230 1.1 christos "R_PRU_DIFF8", /* name */ 231 1.1.1.4 christos false, /* partial_inplace */ 232 1.1 christos 0, /* src_mask */ 233 1.1 christos 0xff, /* dst_mask */ 234 1.1.1.4 christos false), /* pcrel_offset */ 235 1.1 christos 236 1.1 christos HOWTO (R_PRU_GNU_DIFF16, /* type */ 237 1.1 christos 0, /* rightshift */ 238 1.1.1.4 christos 2, /* size */ 239 1.1 christos 16, /* bitsize */ 240 1.1.1.4 christos false, /* pc_relative */ 241 1.1 christos 0, /* bitpos */ 242 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 243 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */ 244 1.1 christos "R_PRU_DIFF16", /* name */ 245 1.1.1.4 christos false, /* partial_inplace */ 246 1.1 christos 0, /* src_mask */ 247 1.1 christos 0xffff, /* dst_mask */ 248 1.1.1.4 christos false), /* pcrel_offset */ 249 1.1 christos 250 1.1 christos HOWTO (R_PRU_GNU_DIFF32, /* type */ 251 1.1 christos 0, /* rightshift */ 252 1.1.1.4 christos 4, /* size */ 253 1.1 christos 32, /* bitsize */ 254 1.1.1.4 christos false, /* pc_relative */ 255 1.1 christos 0, /* bitpos */ 256 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 257 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */ 258 1.1 christos "R_PRU_DIFF32", /* name */ 259 1.1.1.4 christos false, /* partial_inplace */ 260 1.1 christos 0, /* src_mask */ 261 1.1 christos 0xffffffff, /* dst_mask */ 262 1.1.1.4 christos false), /* pcrel_offset */ 263 1.1 christos 264 1.1 christos HOWTO (R_PRU_GNU_DIFF16_PMEM, /* type */ 265 1.1 christos 0, /* rightshift */ 266 1.1.1.4 christos 2, /* size */ 267 1.1 christos 16, /* bitsize */ 268 1.1.1.4 christos false, /* pc_relative */ 269 1.1 christos 0, /* bitpos */ 270 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 271 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */ 272 1.1 christos "R_PRU_DIFF16_PMEM", /* name */ 273 1.1.1.4 christos false, /* partial_inplace */ 274 1.1 christos 0, /* src_mask */ 275 1.1 christos 0xffff, /* dst_mask */ 276 1.1.1.4 christos false), /* pcrel_offset */ 277 1.1 christos 278 1.1 christos HOWTO (R_PRU_GNU_DIFF32_PMEM, /* type */ 279 1.1 christos 0, /* rightshift */ 280 1.1.1.4 christos 4, /* size */ 281 1.1 christos 32, /* bitsize */ 282 1.1.1.4 christos false, /* pc_relative */ 283 1.1 christos 0, /* bitpos */ 284 1.1 christos complain_overflow_bitfield, /* complain_on_overflow */ 285 1.1 christos bfd_elf_pru_diff_relocate,/* special_function */ 286 1.1 christos "R_PRU_DIFF32_PMEM", /* name */ 287 1.1.1.4 christos false, /* partial_inplace */ 288 1.1 christos 0, /* src_mask */ 289 1.1 christos 0xffffffff, /* dst_mask */ 290 1.1.1.4 christos false), /* pcrel_offset */ 291 1.1 christos 292 1.1 christos /* Add other relocations here. */ 293 1.1 christos }; 294 1.1 christos 295 1.1 christos static unsigned char elf_code_to_howto_index[R_PRU_ILLEGAL + 1]; 296 1.1 christos 297 1.1 christos /* Return the howto for relocation RTYPE. */ 298 1.1.1.2 christos 299 1.1 christos static reloc_howto_type * 300 1.1 christos lookup_howto (unsigned int rtype) 301 1.1 christos { 302 1.1.1.4 christos static bool initialized = false; 303 1.1 christos int i; 304 1.1 christos int howto_tbl_size = (int) (sizeof (elf_pru_howto_table_rel) 305 1.1 christos / sizeof (elf_pru_howto_table_rel[0])); 306 1.1 christos 307 1.1.1.2 christos if (! initialized) 308 1.1 christos { 309 1.1.1.4 christos initialized = true; 310 1.1 christos memset (elf_code_to_howto_index, 0xff, 311 1.1 christos sizeof (elf_code_to_howto_index)); 312 1.1 christos for (i = 0; i < howto_tbl_size; i++) 313 1.1 christos elf_code_to_howto_index[elf_pru_howto_table_rel[i].type] = i; 314 1.1 christos } 315 1.1 christos 316 1.1.1.2 christos if (rtype > R_PRU_ILLEGAL) 317 1.1.1.2 christos return NULL; 318 1.1 christos i = elf_code_to_howto_index[rtype]; 319 1.1 christos if (i >= howto_tbl_size) 320 1.1.1.2 christos return NULL; 321 1.1 christos return elf_pru_howto_table_rel + i; 322 1.1 christos } 323 1.1 christos 324 1.1 christos /* Map for converting BFD reloc types to PRU reloc types. */ 325 1.1.1.2 christos 326 1.1 christos struct elf_reloc_map 327 1.1 christos { 328 1.1 christos bfd_reloc_code_real_type bfd_val; 329 1.1 christos enum elf_pru_reloc_type elf_val; 330 1.1 christos }; 331 1.1 christos 332 1.1.1.2 christos static const struct elf_reloc_map pru_reloc_map[] = 333 1.1.1.2 christos { 334 1.1 christos {BFD_RELOC_NONE, R_PRU_NONE}, 335 1.1 christos {BFD_RELOC_PRU_16_PMEM, R_PRU_16_PMEM}, 336 1.1 christos {BFD_RELOC_PRU_U16_PMEMIMM, R_PRU_U16_PMEMIMM}, 337 1.1 christos {BFD_RELOC_16, R_PRU_BFD_RELOC_16}, 338 1.1 christos {BFD_RELOC_PRU_U16, R_PRU_U16}, 339 1.1 christos {BFD_RELOC_PRU_32_PMEM, R_PRU_32_PMEM}, 340 1.1 christos {BFD_RELOC_32, R_PRU_BFD_RELOC_32}, 341 1.1 christos {BFD_RELOC_PRU_S10_PCREL, R_PRU_S10_PCREL}, 342 1.1 christos {BFD_RELOC_PRU_U8_PCREL, R_PRU_U8_PCREL}, 343 1.1 christos {BFD_RELOC_PRU_LDI32, R_PRU_LDI32}, 344 1.1 christos 345 1.1 christos {BFD_RELOC_8, R_PRU_GNU_BFD_RELOC_8}, 346 1.1 christos {BFD_RELOC_PRU_GNU_DIFF8, R_PRU_GNU_DIFF8}, 347 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16, R_PRU_GNU_DIFF16}, 348 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32, R_PRU_GNU_DIFF32}, 349 1.1 christos {BFD_RELOC_PRU_GNU_DIFF16_PMEM, R_PRU_GNU_DIFF16_PMEM}, 350 1.1 christos {BFD_RELOC_PRU_GNU_DIFF32_PMEM, R_PRU_GNU_DIFF32_PMEM}, 351 1.1 christos }; 352 1.1 christos 353 1.1 christos 354 1.1 christos /* Assorted hash table functions. */ 355 1.1 christos 356 1.1 christos /* Create an entry in a PRU ELF linker hash table. */ 357 1.1.1.2 christos 358 1.1 christos static struct bfd_hash_entry * 359 1.1 christos link_hash_newfunc (struct bfd_hash_entry *entry, 360 1.1 christos struct bfd_hash_table *table, const char *string) 361 1.1 christos { 362 1.1 christos /* Allocate the structure if it has not already been allocated by a 363 1.1 christos subclass. */ 364 1.1 christos if (entry == NULL) 365 1.1 christos { 366 1.1 christos entry = bfd_hash_allocate (table, 367 1.1 christos sizeof (struct elf_link_hash_entry)); 368 1.1 christos if (entry == NULL) 369 1.1 christos return entry; 370 1.1 christos } 371 1.1 christos 372 1.1 christos /* Call the allocation method of the superclass. */ 373 1.1 christos entry = _bfd_elf_link_hash_newfunc (entry, table, string); 374 1.1 christos 375 1.1 christos return entry; 376 1.1 christos } 377 1.1 christos 378 1.1 christos /* Implement bfd_elf32_bfd_reloc_type_lookup: 379 1.1 christos Given a BFD reloc type, return a howto structure. */ 380 1.1.1.2 christos 381 1.1 christos static reloc_howto_type * 382 1.1 christos pru_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 383 1.1 christos bfd_reloc_code_real_type code) 384 1.1 christos { 385 1.1.1.2 christos unsigned int i; 386 1.1.1.2 christos 387 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (pru_reloc_map); ++i) 388 1.1 christos if (pru_reloc_map[i].bfd_val == code) 389 1.1 christos return lookup_howto ((unsigned int) pru_reloc_map[i].elf_val); 390 1.1 christos return NULL; 391 1.1 christos } 392 1.1 christos 393 1.1 christos /* Implement bfd_elf32_bfd_reloc_name_lookup: 394 1.1 christos Given a reloc name, return a howto structure. */ 395 1.1.1.2 christos 396 1.1 christos static reloc_howto_type * 397 1.1 christos pru_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 398 1.1 christos const char *r_name) 399 1.1 christos { 400 1.1 christos unsigned int i; 401 1.1.1.2 christos 402 1.1.1.2 christos for (i = 0; i < ARRAY_SIZE (elf_pru_howto_table_rel); i++) 403 1.1 christos if (elf_pru_howto_table_rel[i].name 404 1.1 christos && strcasecmp (elf_pru_howto_table_rel[i].name, r_name) == 0) 405 1.1 christos return &elf_pru_howto_table_rel[i]; 406 1.1 christos 407 1.1 christos return NULL; 408 1.1 christos } 409 1.1 christos 410 1.1 christos /* Implement elf_info_to_howto: 411 1.1 christos Given a ELF32 relocation, fill in a arelent structure. */ 412 1.1.1.2 christos 413 1.1.1.4 christos static bool 414 1.1.1.2 christos pru_elf32_info_to_howto (bfd *abfd, arelent *cache_ptr, 415 1.1 christos Elf_Internal_Rela *dst) 416 1.1 christos { 417 1.1 christos unsigned int r_type; 418 1.1 christos 419 1.1 christos r_type = ELF32_R_TYPE (dst->r_info); 420 1.1.1.2 christos if (r_type >= R_PRU_ILLEGAL) 421 1.1.1.2 christos { 422 1.1.1.2 christos /* xgettext:c-format */ 423 1.1.1.2 christos _bfd_error_handler (_("%pB: unsupported relocation type %#x"), abfd, r_type); 424 1.1.1.2 christos bfd_set_error (bfd_error_bad_value); 425 1.1.1.4 christos return false; 426 1.1.1.2 christos } 427 1.1.1.3 christos 428 1.1 christos cache_ptr->howto = lookup_howto (r_type); 429 1.1.1.2 christos return cache_ptr->howto != NULL; 430 1.1 christos } 431 1.1 christos 432 1.1 christos /* Do the relocations that require special handling. */ 433 1.1 christos /* Produce a word address for program memory. Linker scripts will put .text 434 1.1 christos at a high offset in order to differentiate it from .data. So here we also 435 1.1 christos mask the high bits of PMEM address. 436 1.1 christos 437 1.1 christos But why 1MB when internal Program Memory much smaller? We want to catch 438 1.1 christos unintended overflows. 439 1.1 christos 440 1.1 christos Why not use (1<<31) as an offset and a mask? Sitara DDRAM usually resides 441 1.1 christos there, and users might want to put some shared carveout memory region in 442 1.1 christos their linker scripts. So 0x80000000 might be a valid .data address. 443 1.1 christos 444 1.1 christos Note that we still keep and pass down the original howto. This way we 445 1.1 christos can reuse this function for several different relocations. */ 446 1.1 christos static bfd_reloc_status_type 447 1.1 christos pru_elf32_do_pmem_relocate (bfd *abfd, reloc_howto_type *howto, 448 1.1 christos asection *input_section, 449 1.1 christos bfd_byte *data, bfd_vma offset, 450 1.1 christos bfd_vma symbol_value, bfd_vma addend) 451 1.1 christos { 452 1.1 christos symbol_value = symbol_value + addend; 453 1.1 christos addend = 0; 454 1.1 christos symbol_value &= 0x3fffff; 455 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section, 456 1.1 christos data, offset, symbol_value, addend); 457 1.1 christos } 458 1.1 christos 459 1.1 christos /* Direct copy of _bfd_final_link_relocate, but with special 460 1.1 christos "fill-in". This copy-paste mumbo jumbo is only needed because BFD 461 1.1 christos cannot deal correctly with non-contiguous bit fields. */ 462 1.1 christos static bfd_reloc_status_type 463 1.1 christos pru_elf32_do_s10_pcrel_relocate (bfd *input_bfd, reloc_howto_type *howto, 464 1.1 christos asection *input_section, 465 1.1 christos bfd_byte *contents, bfd_vma address, 466 1.1 christos bfd_vma relocation, bfd_vma addend) 467 1.1 christos { 468 1.1 christos bfd_byte *location; 469 1.1 christos bfd_vma x = 0; 470 1.1 christos bfd_vma qboff; 471 1.1 christos bfd_reloc_status_type flag = bfd_reloc_ok; 472 1.1 christos 473 1.1 christos /* Sanity check the address. */ 474 1.1 christos if (address > bfd_get_section_limit (input_bfd, input_section)) 475 1.1 christos return bfd_reloc_outofrange; 476 1.1 christos 477 1.1 christos BFD_ASSERT (howto->pc_relative); 478 1.1 christos BFD_ASSERT (howto->pcrel_offset); 479 1.1 christos 480 1.1 christos relocation = relocation + addend - (input_section->output_section->vma 481 1.1 christos + input_section->output_offset) - address; 482 1.1 christos 483 1.1 christos location = contents + address; 484 1.1 christos 485 1.1 christos /* Get the value we are going to relocate. */ 486 1.1 christos BFD_ASSERT (bfd_get_reloc_size (howto) == 4); 487 1.1 christos x = bfd_get_32 (input_bfd, location); 488 1.1 christos 489 1.1 christos qboff = GET_BROFF_SIGNED (x) << howto->rightshift; 490 1.1 christos relocation += qboff; 491 1.1 christos 492 1.1 christos BFD_ASSERT (howto->complain_on_overflow == complain_overflow_bitfield); 493 1.1 christos 494 1.1 christos if (relocation > 2047 && relocation < (bfd_vma)-2048l) 495 1.1 christos flag = bfd_reloc_overflow; 496 1.1 christos 497 1.1 christos /* Check that target address is word-aligned. */ 498 1.1 christos if (relocation & ((1 << howto->rightshift) - 1)) 499 1.1 christos flag = bfd_reloc_outofrange; 500 1.1 christos 501 1.1 christos relocation >>= (bfd_vma) howto->rightshift; 502 1.1 christos 503 1.1 christos /* Fill-in the RELOCATION to the right bits of X. */ 504 1.1 christos SET_BROFF_URAW (x, relocation); 505 1.1 christos 506 1.1 christos bfd_put_32 (input_bfd, x, location); 507 1.1 christos 508 1.1 christos return flag; 509 1.1 christos } 510 1.1 christos 511 1.1 christos static bfd_reloc_status_type 512 1.1 christos pru_elf32_do_u8_pcrel_relocate (bfd *abfd, reloc_howto_type *howto, 513 1.1 christos asection *input_section, 514 1.1 christos bfd_byte *data, bfd_vma offset, 515 1.1 christos bfd_vma symbol_value, bfd_vma addend) 516 1.1 christos { 517 1.1 christos bfd_vma relocation; 518 1.1 christos 519 1.1 christos BFD_ASSERT (howto->pc_relative); 520 1.1 christos BFD_ASSERT (howto->pcrel_offset); 521 1.1 christos 522 1.1 christos relocation = symbol_value + addend - (input_section->output_section->vma 523 1.1 christos + input_section->output_offset) - offset; 524 1.1 christos relocation >>= howto->rightshift; 525 1.1 christos 526 1.1 christos /* 0 and 1 are invalid target labels for LOOP. We cannot 527 1.1 christos encode this info in HOWTO, so catch such cases here. */ 528 1.1 christos if (relocation < 2) 529 1.1 christos return bfd_reloc_outofrange; 530 1.1 christos 531 1.1 christos return _bfd_final_link_relocate (howto, abfd, input_section, 532 1.1 christos data, offset, symbol_value, addend); 533 1.1 christos } 534 1.1 christos 535 1.1 christos /* Idea and code taken from elf32-d30v. */ 536 1.1 christos static bfd_reloc_status_type 537 1.1 christos pru_elf32_do_ldi32_relocate (bfd *abfd, reloc_howto_type *howto, 538 1.1 christos asection *input_section, 539 1.1 christos bfd_byte *data, bfd_vma offset, 540 1.1 christos bfd_vma symbol_value, bfd_vma addend) 541 1.1 christos { 542 1.1.1.4 christos bfd_vma relocation; 543 1.1.1.3 christos bfd_size_type octets = offset * OCTETS_PER_BYTE (abfd, input_section); 544 1.1 christos bfd_byte *location; 545 1.1.1.2 christos unsigned long in1, in2; 546 1.1 christos 547 1.1 christos /* A hacked-up version of _bfd_final_link_relocate() follows. */ 548 1.1 christos 549 1.1 christos /* Sanity check the address. */ 550 1.1 christos if (octets + bfd_get_reloc_size (howto) 551 1.1 christos > bfd_get_section_limit_octets (abfd, input_section)) 552 1.1 christos return bfd_reloc_outofrange; 553 1.1 christos 554 1.1 christos /* This function assumes that we are dealing with a basic relocation 555 1.1 christos against a symbol. We want to compute the value of the symbol to 556 1.1 christos relocate to. This is just VALUE, the value of the symbol, plus 557 1.1 christos ADDEND, any addend associated with the reloc. */ 558 1.1 christos relocation = symbol_value + addend; 559 1.1 christos 560 1.1 christos BFD_ASSERT (!howto->pc_relative); 561 1.1 christos 562 1.1 christos /* A hacked-up version of _bfd_relocate_contents() follows. */ 563 1.1.1.3 christos location = data + octets; 564 1.1 christos 565 1.1 christos BFD_ASSERT (!howto->pc_relative); 566 1.1 christos 567 1.1 christos in1 = bfd_get_32 (abfd, location); 568 1.1 christos in2 = bfd_get_32 (abfd, location + 4); 569 1.1 christos 570 1.1.1.2 christos SET_INSN_FIELD (IMM16, in1, relocation >> 16); 571 1.1.1.2 christos SET_INSN_FIELD (IMM16, in2, relocation & 0xffff); 572 1.1 christos 573 1.1 christos bfd_put_32 (abfd, in1, location); 574 1.1 christos bfd_put_32 (abfd, in2, location + 4); 575 1.1 christos 576 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two 577 1.1.1.2 christos LDI instructions are swapped. Detect such object 578 1.1.1.2 christos files and bail. */ 579 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, in1) != RSEL_31_16) 580 1.1.1.2 christos { 581 1.1.1.2 christos /* xgettext:c-format */ 582 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"), 583 1.1.1.2 christos abfd); 584 1.1.1.2 christos return bfd_reloc_notsupported; 585 1.1.1.2 christos } 586 1.1.1.2 christos 587 1.1 christos return bfd_reloc_ok; 588 1.1 christos } 589 1.1 christos 590 1.1 christos /* HOWTO handlers for relocations that require special handling. */ 591 1.1 christos 592 1.1 christos static bfd_reloc_status_type 593 1.1 christos pru_elf32_pmem_relocate (bfd *abfd, arelent *reloc_entry, 594 1.1 christos asymbol *symbol, void *data, 595 1.1 christos asection *input_section, bfd *output_bfd, 596 1.1 christos char **error_message) 597 1.1 christos { 598 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just 599 1.1 christos call the generic function. Any adjustment will be done at final 600 1.1 christos link time. */ 601 1.1 christos if (output_bfd != NULL) 602 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 603 1.1 christos input_section, output_bfd, error_message); 604 1.1 christos 605 1.1.1.2 christos BFD_ASSERT (0); 606 1.1 christos return pru_elf32_do_pmem_relocate (abfd, reloc_entry->howto, 607 1.1 christos input_section, 608 1.1 christos data, reloc_entry->address, 609 1.1 christos (symbol->value 610 1.1 christos + symbol->section->output_section->vma 611 1.1 christos + symbol->section->output_offset), 612 1.1 christos reloc_entry->addend); 613 1.1 christos } 614 1.1 christos 615 1.1 christos static bfd_reloc_status_type 616 1.1 christos pru_elf32_s10_pcrel_relocate (bfd *abfd, arelent *reloc_entry, 617 1.1 christos asymbol *symbol, void *data, 618 1.1 christos asection *input_section, bfd *output_bfd, 619 1.1 christos char **error_message) 620 1.1 christos { 621 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just 622 1.1 christos call the generic function. Any adjustment will be done at final 623 1.1 christos link time. */ 624 1.1 christos if (output_bfd != NULL) 625 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 626 1.1 christos input_section, output_bfd, error_message); 627 1.1 christos 628 1.1 christos return pru_elf32_do_s10_pcrel_relocate (abfd, reloc_entry->howto, 629 1.1 christos input_section, data, 630 1.1 christos reloc_entry->address, 631 1.1 christos (symbol->value 632 1.1 christos + symbol->section->output_section->vma 633 1.1 christos + symbol->section->output_offset), 634 1.1 christos reloc_entry->addend); 635 1.1 christos } 636 1.1 christos 637 1.1 christos static bfd_reloc_status_type 638 1.1 christos pru_elf32_u8_pcrel_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 639 1.1 christos void *data, asection *input_section, 640 1.1 christos bfd *output_bfd, 641 1.1 christos char **error_message) 642 1.1 christos { 643 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just 644 1.1 christos call the generic function. Any adjustment will be done at final 645 1.1 christos link time. */ 646 1.1 christos if (output_bfd != NULL) 647 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 648 1.1 christos input_section, output_bfd, error_message); 649 1.1 christos 650 1.1 christos return pru_elf32_do_u8_pcrel_relocate (abfd, reloc_entry->howto, 651 1.1 christos input_section, 652 1.1 christos data, reloc_entry->address, 653 1.1 christos (symbol->value 654 1.1 christos + symbol->section->output_section->vma 655 1.1 christos + symbol->section->output_offset), 656 1.1 christos reloc_entry->addend); 657 1.1 christos } 658 1.1 christos 659 1.1 christos static bfd_reloc_status_type 660 1.1 christos pru_elf32_ldi32_relocate (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 661 1.1 christos void *data, asection *input_section, 662 1.1 christos bfd *output_bfd, 663 1.1 christos char **error_message) 664 1.1 christos { 665 1.1 christos /* If this is a relocatable link (output_bfd test tells us), just 666 1.1 christos call the generic function. Any adjustment will be done at final 667 1.1 christos link time. */ 668 1.1 christos if (output_bfd != NULL) 669 1.1 christos return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 670 1.1 christos input_section, output_bfd, error_message); 671 1.1 christos 672 1.1 christos return pru_elf32_do_ldi32_relocate (abfd, reloc_entry->howto, 673 1.1 christos input_section, 674 1.1 christos data, reloc_entry->address, 675 1.1 christos (symbol->value 676 1.1 christos + symbol->section->output_section->vma 677 1.1 christos + symbol->section->output_offset), 678 1.1 christos reloc_entry->addend); 679 1.1 christos } 680 1.1 christos 681 1.1 christos 682 1.1 christos /* Implement elf_backend_relocate_section. */ 683 1.1.1.4 christos static int 684 1.1 christos pru_elf32_relocate_section (bfd *output_bfd, 685 1.1 christos struct bfd_link_info *info, 686 1.1 christos bfd *input_bfd, 687 1.1 christos asection *input_section, 688 1.1 christos bfd_byte *contents, 689 1.1 christos Elf_Internal_Rela *relocs, 690 1.1 christos Elf_Internal_Sym *local_syms, 691 1.1 christos asection **local_sections) 692 1.1 christos { 693 1.1.1.2 christos struct bfd_elf_section_data * esd = elf_section_data (input_section); 694 1.1 christos Elf_Internal_Shdr *symtab_hdr; 695 1.1 christos struct elf_link_hash_entry **sym_hashes; 696 1.1 christos Elf_Internal_Rela *rel; 697 1.1 christos Elf_Internal_Rela *relend; 698 1.1.1.4 christos bool is_rel_reloc; 699 1.1 christos 700 1.1 christos symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 701 1.1 christos sym_hashes = elf_sym_hashes (input_bfd); 702 1.1 christos relend = relocs + input_section->reloc_count; 703 1.1 christos 704 1.1.1.2 christos /* See if we have a REL type relocation. */ 705 1.1.1.2 christos is_rel_reloc = (esd->rel.hdr != NULL); 706 1.1.1.2 christos /* Sanity check - only one type of relocation per section. 707 1.1.1.2 christos FIXME: Theoretically it is possible to have both types, 708 1.1.1.2 christos but if that happens how can we distinguish between the two ? */ 709 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || ! esd->rela.hdr); 710 1.1.1.2 christos 711 1.1 christos for (rel = relocs; rel < relend; rel++) 712 1.1 christos { 713 1.1 christos reloc_howto_type *howto; 714 1.1 christos unsigned long r_symndx; 715 1.1 christos Elf_Internal_Sym *sym; 716 1.1 christos asection *sec; 717 1.1 christos struct elf_link_hash_entry *h; 718 1.1 christos bfd_vma relocation; 719 1.1 christos bfd_reloc_status_type r = bfd_reloc_ok; 720 1.1 christos const char *name = NULL; 721 1.1 christos const char* msg = (const char*) NULL; 722 1.1.1.4 christos bool unresolved_reloc; 723 1.1.1.2 christos bfd_vma addend; 724 1.1.1.2 christos 725 1.1.1.2 christos /* If we are using a REL relocation then the addend should be empty. */ 726 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc || rel->r_addend == 0); 727 1.1 christos 728 1.1 christos r_symndx = ELF32_R_SYM (rel->r_info); 729 1.1 christos 730 1.1 christos howto = lookup_howto ((unsigned) ELF32_R_TYPE (rel->r_info)); 731 1.1 christos h = NULL; 732 1.1 christos sym = NULL; 733 1.1 christos sec = NULL; 734 1.1 christos 735 1.1 christos if (r_symndx < symtab_hdr->sh_info) 736 1.1 christos { 737 1.1 christos sym = local_syms + r_symndx; 738 1.1 christos sec = local_sections[r_symndx]; 739 1.1 christos relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 740 1.1 christos } 741 1.1 christos else 742 1.1 christos { 743 1.1.1.4 christos bool warned, ignored; 744 1.1 christos 745 1.1 christos RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 746 1.1 christos r_symndx, symtab_hdr, sym_hashes, 747 1.1 christos h, sec, relocation, 748 1.1 christos unresolved_reloc, warned, ignored); 749 1.1 christos } 750 1.1 christos 751 1.1 christos if (sec && discarded_section (sec)) 752 1.1 christos RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, 753 1.1.1.7 christos rel, 1, relend, R_PRU_NONE, 754 1.1.1.7 christos howto, 0, contents); 755 1.1 christos 756 1.1 christos /* Nothing more to do unless this is a final link. */ 757 1.1 christos if (bfd_link_relocatable (info)) 758 1.1 christos continue; 759 1.1 christos 760 1.1 christos if (howto) 761 1.1 christos { 762 1.1 christos switch (howto->type) 763 1.1 christos { 764 1.1 christos case R_PRU_NONE: 765 1.1 christos /* We don't need to find a value for this symbol. It's just a 766 1.1 christos marker. */ 767 1.1 christos r = bfd_reloc_ok; 768 1.1 christos break; 769 1.1 christos 770 1.1.1.2 christos case R_PRU_U16: 771 1.1.1.2 christos if (is_rel_reloc) 772 1.1.1.2 christos { 773 1.1.1.2 christos unsigned long insn; 774 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset); 775 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn); 776 1.1.1.2 christos } 777 1.1.1.2 christos else 778 1.1.1.2 christos addend = rel->r_addend; 779 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd, 780 1.1.1.2 christos input_section, contents, 781 1.1.1.2 christos rel->r_offset, relocation, 782 1.1.1.2 christos addend); 783 1.1.1.2 christos break; 784 1.1.1.2 christos 785 1.1 christos case R_PRU_U16_PMEMIMM: 786 1.1 christos case R_PRU_32_PMEM: 787 1.1 christos case R_PRU_16_PMEM: 788 1.1.1.2 christos if (is_rel_reloc && howto->type == R_PRU_U16_PMEMIMM) 789 1.1.1.2 christos { 790 1.1.1.2 christos unsigned long insn; 791 1.1.1.2 christos insn = bfd_get_32 (input_bfd, contents + rel->r_offset); 792 1.1.1.2 christos addend = GET_INSN_FIELD (IMM16, insn) << 2; 793 1.1.1.2 christos } 794 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_32_PMEM) 795 1.1.1.2 christos { 796 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset); 797 1.1.1.2 christos addend <<= 2; 798 1.1.1.2 christos } 799 1.1.1.2 christos else if (is_rel_reloc && howto->type == R_PRU_16_PMEM) 800 1.1.1.2 christos { 801 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset); 802 1.1.1.2 christos addend <<= 2; 803 1.1.1.2 christos } 804 1.1.1.2 christos else 805 1.1.1.2 christos { 806 1.1.1.2 christos BFD_ASSERT (!is_rel_reloc); 807 1.1.1.2 christos addend = rel->r_addend; 808 1.1.1.2 christos } 809 1.1 christos r = pru_elf32_do_pmem_relocate (input_bfd, howto, 810 1.1 christos input_section, 811 1.1 christos contents, rel->r_offset, 812 1.1.1.2 christos relocation, addend); 813 1.1 christos break; 814 1.1 christos case R_PRU_S10_PCREL: 815 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc); 816 1.1 christos r = pru_elf32_do_s10_pcrel_relocate (input_bfd, howto, 817 1.1 christos input_section, 818 1.1 christos contents, 819 1.1 christos rel->r_offset, 820 1.1 christos relocation, 821 1.1 christos rel->r_addend); 822 1.1 christos break; 823 1.1 christos case R_PRU_U8_PCREL: 824 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc); 825 1.1 christos r = pru_elf32_do_u8_pcrel_relocate (input_bfd, howto, 826 1.1 christos input_section, 827 1.1 christos contents, 828 1.1 christos rel->r_offset, 829 1.1 christos relocation, 830 1.1 christos rel->r_addend); 831 1.1 christos break; 832 1.1 christos case R_PRU_LDI32: 833 1.1.1.2 christos if (is_rel_reloc) 834 1.1.1.2 christos { 835 1.1.1.2 christos unsigned long in1, in2; 836 1.1.1.2 christos in1 = bfd_get_32 (input_bfd, contents + rel->r_offset); 837 1.1.1.2 christos in2 = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); 838 1.1.1.2 christos addend = (GET_INSN_FIELD (IMM16, in1) << 16) 839 1.1.1.2 christos | GET_INSN_FIELD (IMM16, in2); 840 1.1.1.2 christos } 841 1.1.1.2 christos else 842 1.1.1.2 christos { 843 1.1.1.2 christos addend = rel->r_addend; 844 1.1.1.2 christos } 845 1.1 christos r = pru_elf32_do_ldi32_relocate (input_bfd, howto, 846 1.1 christos input_section, 847 1.1 christos contents, 848 1.1 christos rel->r_offset, 849 1.1 christos relocation, 850 1.1.1.2 christos addend); 851 1.1 christos break; 852 1.1 christos case R_PRU_GNU_DIFF8: 853 1.1 christos case R_PRU_GNU_DIFF16: 854 1.1 christos case R_PRU_GNU_DIFF32: 855 1.1 christos case R_PRU_GNU_DIFF16_PMEM: 856 1.1 christos case R_PRU_GNU_DIFF32_PMEM: 857 1.1.1.2 christos /* GNU extensions support only rela. */ 858 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc); 859 1.1 christos /* Nothing to do here, as contents already contain the 860 1.1 christos diff value. */ 861 1.1 christos r = bfd_reloc_ok; 862 1.1 christos break; 863 1.1 christos 864 1.1.1.2 christos case R_PRU_BFD_RELOC_16: 865 1.1.1.2 christos if (is_rel_reloc) 866 1.1.1.2 christos addend = bfd_get_16 (input_bfd, contents + rel->r_offset); 867 1.1.1.2 christos else 868 1.1.1.2 christos addend = rel->r_addend; 869 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd, 870 1.1.1.2 christos input_section, contents, 871 1.1.1.2 christos rel->r_offset, relocation, 872 1.1.1.2 christos addend); 873 1.1.1.2 christos break; 874 1.1.1.2 christos 875 1.1.1.2 christos case R_PRU_BFD_RELOC_32: 876 1.1.1.2 christos if (is_rel_reloc) 877 1.1.1.2 christos addend = bfd_get_32 (input_bfd, contents + rel->r_offset); 878 1.1.1.2 christos else 879 1.1.1.2 christos addend = rel->r_addend; 880 1.1.1.2 christos r = _bfd_final_link_relocate (howto, input_bfd, 881 1.1.1.2 christos input_section, contents, 882 1.1.1.2 christos rel->r_offset, relocation, 883 1.1.1.2 christos addend); 884 1.1.1.2 christos break; 885 1.1.1.2 christos 886 1.1.1.2 christos case R_PRU_GNU_BFD_RELOC_8: 887 1.1.1.2 christos BFD_ASSERT (! is_rel_reloc); 888 1.1 christos r = _bfd_final_link_relocate (howto, input_bfd, 889 1.1 christos input_section, contents, 890 1.1 christos rel->r_offset, relocation, 891 1.1 christos rel->r_addend); 892 1.1 christos break; 893 1.1.1.2 christos 894 1.1.1.2 christos default: 895 1.1.1.2 christos BFD_ASSERT (0); 896 1.1.1.2 christos break; 897 1.1 christos } 898 1.1 christos } 899 1.1 christos else 900 1.1 christos r = bfd_reloc_notsupported; 901 1.1 christos 902 1.1 christos if (r != bfd_reloc_ok) 903 1.1 christos { 904 1.1 christos if (h != NULL) 905 1.1 christos name = h->root.root.string; 906 1.1 christos else 907 1.1 christos { 908 1.1 christos name = bfd_elf_string_from_elf_section (input_bfd, 909 1.1 christos symtab_hdr->sh_link, 910 1.1 christos sym->st_name); 911 1.1 christos if (name == NULL || *name == '\0') 912 1.1.1.3 christos name = bfd_section_name (sec); 913 1.1 christos } 914 1.1 christos 915 1.1 christos switch (r) 916 1.1 christos { 917 1.1 christos case bfd_reloc_overflow: 918 1.1 christos (*info->callbacks->reloc_overflow) (info, NULL, name, 919 1.1 christos howto->name, (bfd_vma) 0, 920 1.1 christos input_bfd, input_section, 921 1.1 christos rel->r_offset); 922 1.1 christos break; 923 1.1 christos 924 1.1 christos case bfd_reloc_undefined: 925 1.1 christos (*info->callbacks->undefined_symbol) (info, name, input_bfd, 926 1.1 christos input_section, 927 1.1.1.4 christos rel->r_offset, true); 928 1.1 christos break; 929 1.1 christos 930 1.1 christos case bfd_reloc_outofrange: 931 1.1 christos if (msg == NULL) 932 1.1 christos msg = _("relocation out of range"); 933 1.1 christos break; 934 1.1 christos 935 1.1 christos case bfd_reloc_notsupported: 936 1.1 christos if (msg == NULL) 937 1.1 christos msg = _("unsupported relocation"); 938 1.1 christos break; 939 1.1 christos 940 1.1 christos case bfd_reloc_dangerous: 941 1.1 christos if (msg == NULL) 942 1.1 christos msg = _("dangerous relocation"); 943 1.1 christos break; 944 1.1 christos 945 1.1 christos default: 946 1.1 christos if (msg == NULL) 947 1.1 christos msg = _("unknown error"); 948 1.1 christos break; 949 1.1 christos } 950 1.1 christos 951 1.1 christos if (msg) 952 1.1 christos { 953 1.1 christos (*info->callbacks->warning) (info, msg, name, input_bfd, 954 1.1 christos input_section, rel->r_offset); 955 1.1.1.4 christos return false; 956 1.1 christos } 957 1.1 christos } 958 1.1 christos } 959 1.1.1.4 christos return true; 960 1.1 christos } 961 1.1 christos 962 1.1 christos 963 1.1 christos /* Perform a diff relocation. Nothing to do, as the difference value is 965 1.1 christos already written into the section's contents. */ 966 1.1 christos 967 1.1 christos static bfd_reloc_status_type 968 1.1 christos bfd_elf_pru_diff_relocate (bfd *abfd ATTRIBUTE_UNUSED, 969 1.1 christos arelent *reloc_entry ATTRIBUTE_UNUSED, 970 1.1 christos asymbol *symbol ATTRIBUTE_UNUSED, 971 1.1 christos void *data ATTRIBUTE_UNUSED, 972 1.1 christos asection *input_section ATTRIBUTE_UNUSED, 973 1.1 christos bfd *output_bfd ATTRIBUTE_UNUSED, 974 1.1 christos char **error_message ATTRIBUTE_UNUSED) 975 1.1 christos { 976 1.1 christos return bfd_reloc_ok; 977 1.1 christos } 978 1.1 christos 979 1.1 christos 980 1.1 christos /* Returns whether the relocation type passed is a diff reloc. */ 981 1.1.1.4 christos 982 1.1 christos static bool 983 1.1 christos elf32_pru_is_diff_reloc (Elf_Internal_Rela *irel) 984 1.1 christos { 985 1.1 christos return (ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF8 986 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16 987 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32 988 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF16_PMEM 989 1.1 christos || ELF32_R_TYPE (irel->r_info) == R_PRU_GNU_DIFF32_PMEM); 990 1.1 christos } 991 1.1 christos 992 1.1 christos /* Reduce the diff value written in the section by count if the shrinked 993 1.1 christos insn address happens to fall between the two symbols for which this 994 1.1 christos diff reloc was emitted. */ 995 1.1 christos 996 1.1 christos static void 997 1.1 christos elf32_pru_adjust_diff_reloc_value (bfd *abfd, 998 1.1 christos struct bfd_section *isec, 999 1.1 christos Elf_Internal_Rela *irel, 1000 1.1 christos bfd_vma symval, 1001 1.1 christos bfd_vma shrinked_insn_address, 1002 1.1 christos int count) 1003 1.1 christos { 1004 1.1 christos unsigned char *reloc_contents = NULL; 1005 1.1 christos unsigned char *isec_contents = elf_section_data (isec)->this_hdr.contents; 1006 1.1 christos if (isec_contents == NULL) 1007 1.1 christos { 1008 1.1 christos if (! bfd_malloc_and_get_section (abfd, isec, &isec_contents)) 1009 1.1 christos return; 1010 1.1 christos 1011 1.1 christos elf_section_data (isec)->this_hdr.contents = isec_contents; 1012 1.1 christos } 1013 1.1 christos 1014 1.1 christos reloc_contents = isec_contents + irel->r_offset; 1015 1.1 christos 1016 1.1 christos /* Read value written in object file. */ 1017 1.1 christos bfd_signed_vma x = 0; 1018 1.1 christos switch (ELF32_R_TYPE (irel->r_info)) 1019 1.1 christos { 1020 1.1 christos case R_PRU_GNU_DIFF8: 1021 1.1 christos { 1022 1.1 christos x = bfd_get_signed_8 (abfd, reloc_contents); 1023 1.1 christos break; 1024 1.1 christos } 1025 1.1 christos case R_PRU_GNU_DIFF16: 1026 1.1 christos { 1027 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents); 1028 1.1 christos break; 1029 1.1 christos } 1030 1.1 christos case R_PRU_GNU_DIFF32: 1031 1.1 christos { 1032 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents); 1033 1.1 christos break; 1034 1.1 christos } 1035 1.1 christos case R_PRU_GNU_DIFF16_PMEM: 1036 1.1 christos { 1037 1.1 christos x = bfd_get_signed_16 (abfd, reloc_contents) * 4; 1038 1.1 christos break; 1039 1.1 christos } 1040 1.1 christos case R_PRU_GNU_DIFF32_PMEM: 1041 1.1 christos { 1042 1.1 christos x = bfd_get_signed_32 (abfd, reloc_contents) * 4; 1043 1.1 christos break; 1044 1.1 christos } 1045 1.1 christos default: 1046 1.1 christos { 1047 1.1 christos BFD_FAIL (); 1048 1.1 christos } 1049 1.1 christos } 1050 1.1 christos 1051 1.1 christos /* For a diff reloc sym1 - sym2 the diff at assembly time (x) is written 1052 1.1 christos into the object file at the reloc offset. sym2's logical value is 1053 1.1 christos symval (<start_of_section>) + reloc addend. Compute the start and end 1054 1.1 christos addresses and check if the shrinked insn falls between sym1 and sym2. */ 1055 1.1 christos 1056 1.1 christos bfd_vma end_address = symval + irel->r_addend; 1057 1.1 christos bfd_vma start_address = end_address - x; 1058 1.1 christos 1059 1.1 christos /* Shrink the absolute DIFF value (get the to labels "closer" 1060 1.1 christos together), because we have removed data between labels. */ 1061 1.1 christos if (x < 0) 1062 1.1 christos { 1063 1.1 christos x += count; 1064 1.1 christos /* In case the signed x is negative, restore order. */ 1065 1.1 christos SWAP_VALS (end_address, start_address); 1066 1.1 christos } 1067 1.1 christos else 1068 1.1 christos { 1069 1.1 christos x -= count; 1070 1.1 christos } 1071 1.1 christos 1072 1.1 christos /* Reduce the diff value by count bytes and write it back into section 1073 1.1 christos contents. */ 1074 1.1 christos 1075 1.1 christos if (shrinked_insn_address >= start_address 1076 1.1 christos && shrinked_insn_address <= end_address) 1077 1.1 christos { 1078 1.1 christos switch (ELF32_R_TYPE (irel->r_info)) 1079 1.1 christos { 1080 1.1 christos case R_PRU_GNU_DIFF8: 1081 1.1 christos { 1082 1.1 christos bfd_put_signed_8 (abfd, x & 0xFF, reloc_contents); 1083 1.1 christos break; 1084 1.1 christos } 1085 1.1 christos case R_PRU_GNU_DIFF16: 1086 1.1 christos { 1087 1.1 christos bfd_put_signed_16 (abfd, x & 0xFFFF, reloc_contents); 1088 1.1 christos break; 1089 1.1 christos } 1090 1.1 christos case R_PRU_GNU_DIFF32: 1091 1.1 christos { 1092 1.1 christos bfd_put_signed_32 (abfd, x & 0xFFFFFFFF, reloc_contents); 1093 1.1 christos break; 1094 1.1 christos } 1095 1.1 christos case R_PRU_GNU_DIFF16_PMEM: 1096 1.1 christos { 1097 1.1 christos bfd_put_signed_16 (abfd, (x / 4) & 0xFFFF, reloc_contents); 1098 1.1 christos break; 1099 1.1 christos } 1100 1.1 christos case R_PRU_GNU_DIFF32_PMEM: 1101 1.1 christos { 1102 1.1 christos bfd_put_signed_32 (abfd, (x / 4) & 0xFFFFFFFF, reloc_contents); 1103 1.1 christos break; 1104 1.1 christos } 1105 1.1 christos default: 1106 1.1 christos { 1107 1.1 christos BFD_FAIL (); 1108 1.1 christos } 1109 1.1 christos } 1110 1.1 christos 1111 1.1 christos } 1112 1.1 christos } 1113 1.1 christos 1114 1.1 christos /* Delete some bytes from a section while changing the size of an instruction. 1115 1.1 christos The parameter "addr" denotes the section-relative offset pointing just 1116 1.1 christos behind the shrinked instruction. "addr+count" point at the first 1117 1.1 christos byte just behind the original unshrinked instruction. 1118 1.1 christos 1119 1.1 christos Idea copied from the AVR port. */ 1120 1.1.1.4 christos 1121 1.1 christos static bool 1122 1.1 christos pru_elf_relax_delete_bytes (bfd *abfd, 1123 1.1 christos asection *sec, 1124 1.1 christos bfd_vma addr, 1125 1.1 christos int count) 1126 1.1 christos { 1127 1.1 christos Elf_Internal_Shdr *symtab_hdr; 1128 1.1 christos unsigned int sec_shndx; 1129 1.1 christos bfd_byte *contents; 1130 1.1 christos Elf_Internal_Rela *irel, *irelend; 1131 1.1 christos Elf_Internal_Sym *isym; 1132 1.1 christos Elf_Internal_Sym *isymbuf = NULL; 1133 1.1 christos bfd_vma toaddr; 1134 1.1 christos struct elf_link_hash_entry **sym_hashes; 1135 1.1 christos struct elf_link_hash_entry **end_hashes; 1136 1.1 christos unsigned int symcount; 1137 1.1 christos 1138 1.1 christos symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 1139 1.1 christos sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); 1140 1.1 christos contents = elf_section_data (sec)->this_hdr.contents; 1141 1.1 christos 1142 1.1 christos toaddr = sec->size; 1143 1.1 christos 1144 1.1 christos irel = elf_section_data (sec)->relocs; 1145 1.1 christos irelend = irel + sec->reloc_count; 1146 1.1 christos 1147 1.1 christos /* Actually delete the bytes. */ 1148 1.1 christos if (toaddr - addr - count > 0) 1149 1.1 christos memmove (contents + addr, contents + addr + count, 1150 1.1 christos (size_t) (toaddr - addr - count)); 1151 1.1 christos sec->size -= count; 1152 1.1 christos 1153 1.1 christos /* Adjust all the reloc addresses. */ 1154 1.1 christos for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) 1155 1.1 christos { 1156 1.1 christos bfd_vma old_reloc_address; 1157 1.1 christos 1158 1.1 christos old_reloc_address = (sec->output_section->vma 1159 1.1 christos + sec->output_offset + irel->r_offset); 1160 1.1 christos 1161 1.1 christos /* Get the new reloc address. */ 1162 1.1 christos if ((irel->r_offset > addr 1163 1.1 christos && irel->r_offset < toaddr)) 1164 1.1 christos { 1165 1.1 christos if (debug_relax) 1166 1.1 christos printf ("Relocation at address 0x%x needs to be moved.\n" 1167 1.1 christos "Old section offset: 0x%x, New section offset: 0x%x \n", 1168 1.1 christos (unsigned int) old_reloc_address, 1169 1.1 christos (unsigned int) irel->r_offset, 1170 1.1 christos (unsigned int) ((irel->r_offset) - count)); 1171 1.1 christos 1172 1.1 christos irel->r_offset -= count; 1173 1.1 christos } 1174 1.1 christos 1175 1.1 christos } 1176 1.1 christos 1177 1.1 christos /* The reloc's own addresses are now ok. However, we need to readjust 1178 1.1 christos the reloc's addend, i.e. the reloc's value if two conditions are met: 1179 1.1 christos 1.) the reloc is relative to a symbol in this section that 1180 1.1 christos is located in front of the shrinked instruction 1181 1.1 christos 2.) symbol plus addend end up behind the shrinked instruction. 1182 1.1 christos 1183 1.1 christos The most common case where this happens are relocs relative to 1184 1.1 christos the section-start symbol. 1185 1.1 christos 1186 1.1 christos This step needs to be done for all of the sections of the bfd. */ 1187 1.1 christos 1188 1.1 christos { 1189 1.1 christos struct bfd_section *isec; 1190 1.1 christos 1191 1.1 christos for (isec = abfd->sections; isec; isec = isec->next) 1192 1.1 christos { 1193 1.1 christos bfd_vma symval; 1194 1.1 christos bfd_vma shrinked_insn_address; 1195 1.1 christos 1196 1.1 christos if (isec->reloc_count == 0) 1197 1.1 christos continue; 1198 1.1 christos 1199 1.1.1.2 christos shrinked_insn_address = (sec->output_section->vma 1200 1.1 christos + sec->output_offset + addr); 1201 1.1 christos 1202 1.1 christos irel = elf_section_data (isec)->relocs; 1203 1.1 christos /* PR 12161: Read in the relocs for this section if necessary. */ 1204 1.1.1.4 christos if (irel == NULL) 1205 1.1 christos irel = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, true); 1206 1.1 christos 1207 1.1 christos for (irelend = irel + isec->reloc_count; 1208 1.1 christos irel < irelend; 1209 1.1 christos irel++) 1210 1.1 christos { 1211 1.1 christos /* Read this BFD's local symbols if we haven't done 1212 1.1 christos so already. */ 1213 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0) 1214 1.1 christos { 1215 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; 1216 1.1 christos if (isymbuf == NULL) 1217 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, 1218 1.1 christos symtab_hdr->sh_info, 0, 1219 1.1 christos NULL, NULL, NULL); 1220 1.1.1.4 christos if (isymbuf == NULL) 1221 1.1 christos return false; 1222 1.1 christos } 1223 1.1 christos 1224 1.1 christos /* Get the value of the symbol referred to by the reloc. */ 1225 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) 1226 1.1 christos { 1227 1.1 christos /* A local symbol. */ 1228 1.1 christos asection *sym_sec; 1229 1.1 christos 1230 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info); 1231 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); 1232 1.1 christos symval = isym->st_value; 1233 1.1 christos /* If the reloc is absolute, it will not have 1234 1.1 christos a symbol or section associated with it. */ 1235 1.1 christos if (sym_sec == sec) 1236 1.1 christos { 1237 1.1 christos symval += sym_sec->output_section->vma 1238 1.1 christos + sym_sec->output_offset; 1239 1.1 christos 1240 1.1 christos if (debug_relax) 1241 1.1 christos printf ("Checking if the relocation's " 1242 1.1 christos "addend needs corrections.\n" 1243 1.1 christos "Address of anchor symbol: 0x%x \n" 1244 1.1 christos "Address of relocation target: 0x%x \n" 1245 1.1 christos "Address of relaxed insn: 0x%x \n", 1246 1.1 christos (unsigned int) symval, 1247 1.1 christos (unsigned int) (symval + irel->r_addend), 1248 1.1 christos (unsigned int) shrinked_insn_address); 1249 1.1 christos 1250 1.1 christos /* Shrink the special DIFF relocations. */ 1251 1.1 christos if (elf32_pru_is_diff_reloc (irel)) 1252 1.1 christos { 1253 1.1 christos elf32_pru_adjust_diff_reloc_value (abfd, isec, irel, 1254 1.1 christos symval, 1255 1.1 christos shrinked_insn_address, 1256 1.1 christos count); 1257 1.1 christos } 1258 1.1 christos 1259 1.1 christos /* Fix the addend, if it is affected. */ 1260 1.1 christos if (symval <= shrinked_insn_address 1261 1.1 christos && (symval + irel->r_addend) > shrinked_insn_address) 1262 1.1 christos { 1263 1.1 christos 1264 1.1 christos irel->r_addend -= count; 1265 1.1 christos 1266 1.1 christos if (debug_relax) 1267 1.1 christos printf ("Relocation's addend needed to be fixed \n"); 1268 1.1 christos } 1269 1.1 christos } 1270 1.1 christos /* else...Reference symbol is absolute. 1271 1.1 christos No adjustment needed. */ 1272 1.1 christos } 1273 1.1 christos /* else...Reference symbol is extern. No need for adjusting 1274 1.1 christos the addend. */ 1275 1.1 christos } 1276 1.1 christos } 1277 1.1 christos } 1278 1.1 christos 1279 1.1 christos /* Adjust the local symbols defined in this section. */ 1280 1.1 christos isym = (Elf_Internal_Sym *) symtab_hdr->contents; 1281 1.1 christos /* Fix PR 9841, there may be no local symbols. */ 1282 1.1 christos if (isym != NULL) 1283 1.1 christos { 1284 1.1 christos Elf_Internal_Sym *isymend; 1285 1.1 christos 1286 1.1 christos isymend = isym + symtab_hdr->sh_info; 1287 1.1 christos for (; isym < isymend; isym++) 1288 1.1 christos { 1289 1.1 christos if (isym->st_shndx == sec_shndx) 1290 1.1 christos { 1291 1.1 christos if (isym->st_value > addr 1292 1.1 christos && isym->st_value <= toaddr) 1293 1.1 christos isym->st_value -= count; 1294 1.1 christos 1295 1.1 christos if (isym->st_value <= addr 1296 1.1 christos && isym->st_value + isym->st_size > addr) 1297 1.1 christos { 1298 1.1 christos /* If this assert fires then we have a symbol that ends 1299 1.1 christos part way through an instruction. Does that make 1300 1.1 christos sense? */ 1301 1.1 christos BFD_ASSERT (isym->st_value + isym->st_size >= addr + count); 1302 1.1 christos isym->st_size -= count; 1303 1.1 christos } 1304 1.1 christos } 1305 1.1 christos } 1306 1.1 christos } 1307 1.1 christos 1308 1.1 christos /* Now adjust the global symbols defined in this section. */ 1309 1.1 christos symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) 1310 1.1 christos - symtab_hdr->sh_info); 1311 1.1 christos sym_hashes = elf_sym_hashes (abfd); 1312 1.1 christos end_hashes = sym_hashes + symcount; 1313 1.1 christos for (; sym_hashes < end_hashes; sym_hashes++) 1314 1.1 christos { 1315 1.1 christos struct elf_link_hash_entry *sym_hash = *sym_hashes; 1316 1.1 christos if ((sym_hash->root.type == bfd_link_hash_defined 1317 1.1 christos || sym_hash->root.type == bfd_link_hash_defweak) 1318 1.1 christos && sym_hash->root.u.def.section == sec) 1319 1.1 christos { 1320 1.1 christos if (sym_hash->root.u.def.value > addr 1321 1.1 christos && sym_hash->root.u.def.value <= toaddr) 1322 1.1 christos sym_hash->root.u.def.value -= count; 1323 1.1 christos 1324 1.1 christos if (sym_hash->root.u.def.value <= addr 1325 1.1 christos && (sym_hash->root.u.def.value + sym_hash->size > addr)) 1326 1.1 christos { 1327 1.1 christos /* If this assert fires then we have a symbol that ends 1328 1.1 christos part way through an instruction. Does that make 1329 1.1 christos sense? */ 1330 1.1 christos BFD_ASSERT (sym_hash->root.u.def.value + sym_hash->size 1331 1.1 christos >= addr + count); 1332 1.1 christos sym_hash->size -= count; 1333 1.1 christos } 1334 1.1 christos } 1335 1.1 christos } 1336 1.1.1.4 christos 1337 1.1 christos return true; 1338 1.1 christos } 1339 1.1.1.4 christos 1340 1.1.1.4 christos static bool 1341 1.1.1.4 christos pru_elf32_relax_section (bfd *abfd, asection *sec, 1342 1.1.1.4 christos struct bfd_link_info *link_info, 1343 1.1 christos bool *again) 1344 1.1 christos { 1345 1.1 christos Elf_Internal_Shdr * symtab_hdr; 1346 1.1 christos Elf_Internal_Rela * internal_relocs; 1347 1.1 christos Elf_Internal_Rela * irel; 1348 1.1 christos Elf_Internal_Rela * irelend; 1349 1.1 christos bfd_byte * contents = NULL; 1350 1.1 christos Elf_Internal_Sym * isymbuf = NULL; 1351 1.1 christos 1352 1.1.1.4 christos /* Assume nothing changes. */ 1353 1.1 christos *again = false; 1354 1.1 christos 1355 1.1 christos /* We don't have to do anything for a relocatable link, if 1356 1.1 christos this section does not have relocs, or if this is not a 1357 1.1 christos code section. */ 1358 1.1.1.5 christos if (bfd_link_relocatable (link_info) 1359 1.1.1.5 christos || sec->reloc_count == 0 1360 1.1.1.5 christos || (sec->flags & SEC_RELOC) == 0 1361 1.1.1.5 christos || (sec->flags & SEC_HAS_CONTENTS) == 0 1362 1.1.1.4 christos || (sec->flags & SEC_CODE) == 0) 1363 1.1 christos return true; 1364 1.1 christos 1365 1.1 christos symtab_hdr = & elf_tdata (abfd)->symtab_hdr; 1366 1.1 christos 1367 1.1 christos /* Get a copy of the native relocations. */ 1368 1.1 christos internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, 1369 1.1 christos link_info->keep_memory); 1370 1.1 christos if (internal_relocs == NULL) 1371 1.1 christos goto error_return; 1372 1.1 christos 1373 1.1 christos /* Walk through them looking for relaxing opportunities. */ 1374 1.1 christos irelend = internal_relocs + sec->reloc_count; 1375 1.1 christos 1376 1.1 christos for (irel = internal_relocs; irel < irelend; irel++) 1377 1.1 christos { 1378 1.1 christos bfd_vma symval; 1379 1.1 christos 1380 1.1 christos /* Get the section contents if we haven't done so already. */ 1381 1.1 christos if (contents == NULL) 1382 1.1 christos { 1383 1.1 christos /* Get cached copy if it exists. */ 1384 1.1 christos if (elf_section_data (sec)->this_hdr.contents != NULL) 1385 1.1 christos contents = elf_section_data (sec)->this_hdr.contents; 1386 1.1 christos else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) 1387 1.1 christos goto error_return; 1388 1.1 christos } 1389 1.1 christos 1390 1.1 christos /* Read this BFD's local symbols if we haven't done so already. */ 1391 1.1 christos if (isymbuf == NULL && symtab_hdr->sh_info != 0) 1392 1.1 christos { 1393 1.1 christos isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; 1394 1.1 christos if (isymbuf == NULL) 1395 1.1 christos isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, 1396 1.1 christos symtab_hdr->sh_info, 0, 1397 1.1 christos NULL, NULL, NULL); 1398 1.1 christos if (isymbuf == NULL) 1399 1.1 christos goto error_return; 1400 1.1 christos } 1401 1.1 christos 1402 1.1 christos /* Get the value of the symbol referred to by the reloc. */ 1403 1.1 christos if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) 1404 1.1 christos { 1405 1.1 christos /* A local symbol. */ 1406 1.1 christos Elf_Internal_Sym *isym; 1407 1.1 christos asection *sym_sec; 1408 1.1 christos 1409 1.1 christos isym = isymbuf + ELF32_R_SYM (irel->r_info); 1410 1.1 christos if (isym->st_shndx == SHN_UNDEF) 1411 1.1 christos sym_sec = bfd_und_section_ptr; 1412 1.1 christos else if (isym->st_shndx == SHN_ABS) 1413 1.1 christos sym_sec = bfd_abs_section_ptr; 1414 1.1 christos else if (isym->st_shndx == SHN_COMMON) 1415 1.1 christos sym_sec = bfd_com_section_ptr; 1416 1.1 christos else 1417 1.1 christos sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); 1418 1.1 christos symval = (isym->st_value 1419 1.1 christos + sym_sec->output_section->vma + sym_sec->output_offset); 1420 1.1 christos } 1421 1.1 christos else 1422 1.1 christos { 1423 1.1 christos unsigned long indx; 1424 1.1 christos struct elf_link_hash_entry *h; 1425 1.1 christos 1426 1.1 christos /* An external symbol. */ 1427 1.1 christos indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; 1428 1.1 christos h = elf_sym_hashes (abfd)[indx]; 1429 1.1 christos BFD_ASSERT (h != NULL); 1430 1.1 christos 1431 1.1 christos if (h->root.type != bfd_link_hash_defined 1432 1.1 christos && h->root.type != bfd_link_hash_defweak) 1433 1.1 christos /* This appears to be a reference to an undefined 1434 1.1 christos symbol. Just ignore it--it will be caught by the 1435 1.1 christos regular reloc processing. */ 1436 1.1 christos continue; 1437 1.1 christos 1438 1.1 christos symval = (h->root.u.def.value 1439 1.1 christos + h->root.u.def.section->output_section->vma 1440 1.1 christos + h->root.u.def.section->output_offset); 1441 1.1 christos } 1442 1.1 christos 1443 1.1 christos /* For simplicity of coding, we are going to modify the section 1444 1.1 christos contents, the section relocs, and the BFD symbol table. We 1445 1.1 christos must tell the rest of the code not to free up this 1446 1.1 christos information. It would be possible to instead create a table 1447 1.1 christos of changes which have to be made, as is done in coff-mips.c; 1448 1.1 christos that would be more work, but would require less memory when 1449 1.1 christos the linker is run. */ 1450 1.1 christos 1451 1.1 christos /* Check if we can remove an LDI instruction from the LDI32 1452 1.1 christos pseudo instruction if the upper 16 operand bits are zero. */ 1453 1.1 christos if (ELF32_R_TYPE (irel->r_info) == (int) R_PRU_LDI32) 1454 1.1 christos { 1455 1.1 christos bfd_vma value = symval + irel->r_addend; 1456 1.1 christos 1457 1.1 christos if (debug_relax) 1458 1.1 christos printf ("R_PRU_LDI32 with value=0x%lx\n", (long) value); 1459 1.1 christos 1460 1.1 christos if ((long) value >> 16 == 0) 1461 1.1.1.2 christos { 1462 1.1.1.2 christos unsigned long insn; 1463 1.1 christos 1464 1.1 christos /* Note that we've changed the relocs, section contents. */ 1465 1.1 christos elf_section_data (sec)->relocs = internal_relocs; 1466 1.1 christos elf_section_data (sec)->this_hdr.contents = contents; 1467 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf; 1468 1.1.1.2 christos 1469 1.1.1.2 christos /* Make the second instruction load the 16-bit constant 1470 1.1.1.2 christos into the full 32-bit register. */ 1471 1.1.1.2 christos insn = bfd_get_32 (abfd, contents + irel->r_offset + 4); 1472 1.1.1.2 christos 1473 1.1.1.2 christos /* Old GAS and LD versions have a bug, where the two 1474 1.1.1.2 christos LDI instructions are swapped. Detect such object 1475 1.1.1.2 christos files and bail. */ 1476 1.1.1.2 christos if (GET_INSN_FIELD (RDSEL, insn) != RSEL_15_0) 1477 1.1.1.2 christos { 1478 1.1.1.2 christos /* xgettext:c-format */ 1479 1.1.1.2 christos _bfd_error_handler (_("error: %pB: old incompatible object file detected"), 1480 1.1.1.2 christos abfd); 1481 1.1.1.2 christos goto error_return; 1482 1.1.1.2 christos } 1483 1.1.1.2 christos 1484 1.1.1.2 christos SET_INSN_FIELD (RDSEL, insn, RSEL_31_0); 1485 1.1.1.2 christos bfd_put_32 (abfd, insn, contents + irel->r_offset + 4); 1486 1.1.1.2 christos 1487 1.1.1.2 christos /* Delete the first LDI instruction. Note that there should 1488 1.1.1.2 christos be no relocations or symbols pointing to the second LDI 1489 1.1.1.2 christos instruction. */ 1490 1.1 christos if (!pru_elf_relax_delete_bytes (abfd, sec, irel->r_offset, 4)) 1491 1.1 christos goto error_return; 1492 1.1.1.2 christos 1493 1.1.1.2 christos /* We're done with deletion of the first instruction. 1494 1.1 christos Set a regular LDI relocation for the second instruction 1495 1.1 christos we left to load the 16-bit value into the 32-bit 1496 1.1 christos register. */ 1497 1.1 christos irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), 1498 1.1 christos R_PRU_U16); 1499 1.1 christos 1500 1.1 christos /* That will change things, so, we should relax again. 1501 1.1.1.4 christos Note that this is not required, and it may be slow. */ 1502 1.1 christos *again = true; 1503 1.1 christos } 1504 1.1 christos } 1505 1.1 christos } 1506 1.1 christos 1507 1.1 christos if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) 1508 1.1 christos { 1509 1.1 christos if (!link_info->keep_memory) 1510 1.1 christos free (isymbuf); 1511 1.1 christos else 1512 1.1 christos { 1513 1.1 christos /* Cache the symbols for elf_link_input_bfd. */ 1514 1.1 christos symtab_hdr->contents = (unsigned char *) isymbuf; 1515 1.1 christos } 1516 1.1 christos } 1517 1.1 christos 1518 1.1 christos if (contents != NULL 1519 1.1 christos && elf_section_data (sec)->this_hdr.contents != contents) 1520 1.1 christos { 1521 1.1 christos if (!link_info->keep_memory) 1522 1.1 christos free (contents); 1523 1.1 christos else 1524 1.1 christos { 1525 1.1 christos /* Cache the section contents for elf_link_input_bfd. */ 1526 1.1 christos elf_section_data (sec)->this_hdr.contents = contents; 1527 1.1 christos } 1528 1.1 christos } 1529 1.1.1.4 christos 1530 1.1 christos if (elf_section_data (sec)->relocs != internal_relocs) 1531 1.1 christos free (internal_relocs); 1532 1.1.1.4 christos 1533 1.1 christos return true; 1534 1.1.1.4 christos 1535 1.1.1.4 christos error_return: 1536 1.1 christos if (symtab_hdr->contents != (unsigned char *) isymbuf) 1537 1.1.1.4 christos free (isymbuf); 1538 1.1 christos if (elf_section_data (sec)->this_hdr.contents != contents) 1539 1.1.1.4 christos free (contents); 1540 1.1 christos if (elf_section_data (sec)->relocs != internal_relocs) 1541 1.1 christos free (internal_relocs); 1542 1.1.1.4 christos 1543 1.1 christos return false; 1544 1.1 christos } 1545 1.1 christos 1546 1.1 christos /* Free the derived linker hash table. */ 1547 1.1 christos static void 1548 1.1 christos pru_elf32_link_hash_table_free (bfd *obfd) 1549 1.1 christos { 1550 1.1 christos _bfd_elf_link_hash_table_free (obfd); 1551 1.1 christos } 1552 1.1 christos 1553 1.1 christos /* Implement bfd_elf32_bfd_link_hash_table_create. */ 1554 1.1 christos static struct bfd_link_hash_table * 1555 1.1 christos pru_elf32_link_hash_table_create (bfd *abfd) 1556 1.1 christos { 1557 1.1.1.4 christos struct elf_link_hash_table *ret; 1558 1.1 christos size_t amt = sizeof (struct elf_link_hash_table); 1559 1.1 christos 1560 1.1 christos ret = bfd_zmalloc (amt); 1561 1.1 christos if (ret == NULL) 1562 1.1 christos return NULL; 1563 1.1.1.6 christos 1564 1.1.1.6 christos if (!_bfd_elf_link_hash_table_init (ret, abfd, link_hash_newfunc, 1565 1.1 christos sizeof (struct elf_link_hash_entry))) 1566 1.1 christos { 1567 1.1 christos free (ret); 1568 1.1 christos return NULL; 1569 1.1 christos } 1570 1.1 christos 1571 1.1 christos ret->root.hash_table_free = pru_elf32_link_hash_table_free; 1572 1.1 christos 1573 1.1 christos return &ret->root; 1574 1.1 christos } 1575 1.1 christos 1576 1.1 christos #define ELF_ARCH bfd_arch_pru 1577 1.1 christos #define ELF_TARGET_ID PRU_ELF_DATA 1578 1.1 christos #define ELF_MACHINE_CODE EM_TI_PRU 1579 1.1 christos 1580 1.1 christos #define ELF_MAXPAGESIZE 1 1581 1.1 christos 1582 1.1 christos #define bfd_elf32_bfd_link_hash_table_create \ 1583 1.1 christos pru_elf32_link_hash_table_create 1584 1.1 christos 1585 1.1 christos /* Relocation table lookup macros. */ 1586 1.1 christos 1587 1.1 christos #define bfd_elf32_bfd_reloc_type_lookup pru_elf32_bfd_reloc_type_lookup 1588 1.1 christos #define bfd_elf32_bfd_reloc_name_lookup pru_elf32_bfd_reloc_name_lookup 1589 1.1 christos 1590 1.1.1.2 christos #define elf_info_to_howto pru_elf32_info_to_howto 1591 1.1 christos #define elf_info_to_howto_rel NULL 1592 1.1 christos 1593 1.1 christos /* elf backend functions. */ 1594 1.1.1.2 christos 1595 1.1.1.2 christos /* TI folks like to use a mix of REL and RELA relocations. See also 1596 1.1.1.2 christos the MSP430 and TI C6X backends. */ 1597 1.1.1.2 christos #define elf_backend_may_use_rel_p 1 1598 1.1.1.2 christos #define elf_backend_may_use_rela_p 1 1599 1.1.1.2 christos #define elf_backend_default_use_rela_p 1 1600 1.1 christos 1601 1.1 christos #define elf_backend_rela_normal 1 1602 1.1 christos 1603 1.1 christos #define elf_backend_relocate_section pru_elf32_relocate_section 1604 1.1.1.4 christos #define bfd_elf32_bfd_relax_section pru_elf32_relax_section 1605 1.1 christos #define elf_backend_can_gc_sections 1 1606 1.1.1.5 christos 1607 1.1.1.5 christos #define elf_backend_default_execstack 0 1608 1.1 christos 1609 1.1 christos #define TARGET_LITTLE_SYM pru_elf32_vec 1610 1.1 christos #define TARGET_LITTLE_NAME "elf32-pru" 1611 1.1 christos 1612 #include "elf32-target.h" 1613