1 /* D30V-specific support for 32-bit ELF 2 Copyright (C) 1997-2014 Free Software Foundation, Inc. 3 Contributed by Martin Hunt (hunt (at) cygnus.com). 4 5 This file is part of BFD, the Binary File Descriptor library. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 20 MA 02110-1301, USA. */ 21 22 #include "sysdep.h" 23 #include "bfd.h" 24 #include "libbfd.h" 25 #include "elf-bfd.h" 26 #include "elf/d30v.h" 27 28 #define MAX32 ((bfd_signed_vma) 0x7fffffff) 29 #define MIN32 (- MAX32 - 1) 30 31 static bfd_reloc_status_type 32 bfd_elf_d30v_reloc (bfd *abfd, 33 arelent *reloc_entry, 34 asymbol *symbol, 35 void * data, 36 asection *input_section, 37 bfd *output_bfd, 38 char **error_message) 39 { 40 bfd_signed_vma relocation; 41 bfd_vma in1, in2, num; 42 bfd_vma tmp_addr = 0; 43 bfd_reloc_status_type r; 44 asection *reloc_target_output_section; 45 bfd_size_type addr = reloc_entry->address; 46 bfd_reloc_status_type flag = bfd_reloc_ok; 47 bfd_vma output_base = 0; 48 reloc_howto_type *howto = reloc_entry->howto; 49 int make_absolute = 0; 50 51 if (output_bfd != NULL) 52 { 53 /* Partial linking -- do nothing. */ 54 reloc_entry->address += input_section->output_offset; 55 return bfd_reloc_ok; 56 } 57 58 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 59 input_section, output_bfd, error_message); 60 if (r != bfd_reloc_continue) 61 return r; 62 63 /* A hacked-up version of bfd_perform_reloc() follows. */ 64 if (bfd_is_und_section (symbol->section) 65 && (symbol->flags & BSF_WEAK) == 0 66 && output_bfd == NULL) 67 flag = bfd_reloc_undefined; 68 69 /* Is the address of the relocation really within the section? */ 70 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 71 return bfd_reloc_outofrange; 72 73 /* Work out which section the relocation is targeted at and the 74 initial relocation command value. */ 75 76 /* Get symbol value. (Common symbols are special.) */ 77 if (bfd_is_com_section (symbol->section)) 78 relocation = 0; 79 else 80 relocation = symbol->value; 81 82 reloc_target_output_section = symbol->section->output_section; 83 84 /* Convert input-section-relative symbol value to absolute. */ 85 output_base = reloc_target_output_section->vma; 86 relocation += output_base + symbol->section->output_offset; 87 88 /* Add in supplied addend. */ 89 relocation += reloc_entry->addend; 90 91 /* Here the variable relocation holds the final address of the 92 symbol we are relocating against, plus any addend. */ 93 if (howto->pc_relative) 94 { 95 tmp_addr = input_section->output_section->vma 96 + input_section->output_offset 97 + reloc_entry->address; 98 relocation -= tmp_addr; 99 } 100 101 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr); 102 in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4); 103 104 /* Extract the addend. */ 105 num = ((in2 & 0x3FFFF) 106 | ((in2 & 0xFF00000) >> 2) 107 | ((in1 & 0x3F) << 26)); 108 in1 &= 0xFFFFFFC0; 109 in2 = 0x80000000; 110 111 relocation += num; 112 113 if (howto->pc_relative && howto->bitsize == 32) 114 { 115 /* The D30V has a PC that doesn't wrap and PC-relative jumps are 116 signed, so a PC-relative jump can't be more than +/- 2^31 bytes. 117 If one exceeds this, change it to an absolute jump. */ 118 if (relocation > MAX32 || relocation < MIN32) 119 { 120 relocation = (relocation + tmp_addr) & 0xffffffff; 121 make_absolute = 1; 122 } 123 } 124 125 in1 |= (relocation >> 26) & 0x3F; /* Top 6 bits. */ 126 in2 |= ((relocation & 0x03FC0000) << 2); /* Next 8 bits. */ 127 in2 |= relocation & 0x0003FFFF; /* Bottom 18 bits. */ 128 129 /* Change a PC-relative instruction to its 130 absolute equivalent with this simple hack. */ 131 if (make_absolute) 132 in1 |= 0x00100000; 133 134 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr); 135 bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4); 136 137 return flag; 138 } 139 140 static bfd_reloc_status_type 141 bfd_elf_d30v_reloc_21 (bfd *abfd, 142 arelent *reloc_entry, 143 asymbol *symbol, 144 void * data, 145 asection *input_section, 146 bfd *output_bfd, 147 char **error_message) 148 { 149 bfd_vma relocation; 150 bfd_vma in1, num; 151 bfd_reloc_status_type r; 152 asection *reloc_target_output_section; 153 bfd_size_type addr = reloc_entry->address; 154 bfd_reloc_status_type flag = bfd_reloc_ok; 155 bfd_vma output_base = 0; 156 reloc_howto_type *howto = reloc_entry->howto; 157 int mask, max; 158 159 if (output_bfd != NULL) 160 { 161 /* Partial linking -- do nothing. */ 162 reloc_entry->address += input_section->output_offset; 163 return bfd_reloc_ok; 164 } 165 166 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 167 input_section, output_bfd, error_message); 168 if (r != bfd_reloc_continue) 169 return r; 170 171 /* A hacked-up version of bfd_perform_reloc() follows. */ 172 if (bfd_is_und_section (symbol->section) 173 && (symbol->flags & BSF_WEAK) == 0 174 && output_bfd == NULL) 175 flag = bfd_reloc_undefined; 176 177 /* Is the address of the relocation really within the section? */ 178 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 179 return bfd_reloc_outofrange; 180 181 /* Work out which section the relocation is targeted at and the 182 initial relocation command value. */ 183 184 /* Get symbol value. (Common symbols are special.) */ 185 if (bfd_is_com_section (symbol->section)) 186 relocation = 0; 187 else 188 relocation = symbol->value; 189 190 reloc_target_output_section = symbol->section->output_section; 191 192 /* Convert input-section-relative symbol value to absolute. */ 193 output_base = reloc_target_output_section->vma; 194 relocation += output_base + symbol->section->output_offset; 195 196 /* Add in supplied addend. */ 197 relocation += reloc_entry->addend; 198 199 /* Here the variable relocation holds the final address of the 200 symbol we are relocating against, plus any addend. */ 201 202 if (howto->pc_relative) 203 { 204 relocation -= (input_section->output_section->vma 205 + input_section->output_offset); 206 if (howto->pcrel_offset) 207 relocation -= reloc_entry->address; 208 } 209 210 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr); 211 212 mask = (1 << howto->bitsize) - 1; 213 if (howto->bitsize == 6) 214 mask <<= 12; 215 max = (1 << (howto->bitsize + 2)) - 1; 216 217 /* Extract the addend. */ 218 num = in1 & mask; /* 18 bits. */ 219 if (howto->bitsize == 6) 220 num >>= 12; 221 num <<= 3; /* shift left 3. */ 222 in1 &= ~mask; /* Mask out addend. */ 223 224 relocation += num; 225 if (howto->type == R_D30V_21_PCREL_R 226 || howto->type == R_D30V_15_PCREL_R 227 || howto->type == R_D30V_9_PCREL_R) 228 relocation += 4; 229 230 if ((int) relocation < 0) 231 { 232 if (~ (int) relocation > max) 233 flag = bfd_reloc_overflow; 234 } 235 else 236 { 237 if ((int) relocation > max) 238 flag = bfd_reloc_overflow; 239 } 240 241 relocation >>= 3; 242 if (howto->bitsize == 6) 243 in1 |= ((relocation & (mask >> 12)) << 12); 244 else 245 in1 |= relocation & mask; 246 247 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr); 248 249 return flag; 250 } 251 252 static reloc_howto_type elf_d30v_howto_table[] = 253 { 254 /* This reloc does nothing. */ 255 HOWTO (R_D30V_NONE, /* Type. */ 256 0, /* Rightshift. */ 257 2, /* Size (0 = byte, 1 = short, 2 = long). */ 258 32, /* Bitsize. */ 259 FALSE, /* PC_relative. */ 260 0, /* Bitpos. */ 261 complain_overflow_bitfield, /* Complain_on_overflow. */ 262 bfd_elf_generic_reloc, /* Special_function. */ 263 "R_D30V_NONE", /* Name. */ 264 FALSE, /* Partial_inplace. */ 265 0, /* Src_mask. */ 266 0, /* Dst_mask. */ 267 FALSE), /* PCrel_offset. */ 268 269 /* A 6 bit absolute relocation. */ 270 HOWTO (R_D30V_6, /* Type. */ 271 0, /* Rightshift. */ 272 2, /* Size (0 = byte, 1 = short, 2 = long). */ 273 6, /* Bitsize. */ 274 FALSE, /* PC_relative. */ 275 0, /* Bitpos. */ 276 complain_overflow_bitfield, /* Complain_on_overflow. */ 277 bfd_elf_generic_reloc, /* Special_function. */ 278 "R_D30V_6", /* Name. */ 279 FALSE, /* Partial_inplace. */ 280 0x3f, /* Src_mask. */ 281 0x3f, /* Dst_mask. */ 282 FALSE), /* PCrel_offset. */ 283 284 /* A relative 9 bit relocation, right shifted by 3. */ 285 HOWTO (R_D30V_9_PCREL, /* Type. */ 286 3, /* Rightshift. */ 287 2, /* Size (0 = byte, 1 = short, 2 = long). */ 288 6, /* Bitsize. */ 289 TRUE, /* PC_relative. */ 290 0, /* Bitpos. */ 291 complain_overflow_signed, /* Complain_on_overflow. */ 292 bfd_elf_d30v_reloc_21, /* Special_function. */ 293 "R_D30V_9_PCREL", /* Name. */ 294 FALSE, /* Partial_inplace. */ 295 0x3f, /* Src_mask. */ 296 0x3f, /* Dst_mask. */ 297 TRUE), /* PCrel_offset. */ 298 299 /* A relative 9 bit relocation, right shifted by 3. */ 300 HOWTO (R_D30V_9_PCREL_R, /* Type. */ 301 3, /* Rightshift. */ 302 2, /* Size (0 = byte, 1 = short, 2 = long). */ 303 6, /* Bitsize. */ 304 TRUE, /* PC_relative. */ 305 0, /* Bitpos. */ 306 complain_overflow_signed, /* Complain_on_overflow. */ 307 bfd_elf_d30v_reloc_21, /* Special_function. */ 308 "R_D30V_9_PCREL_R", /* Name. */ 309 FALSE, /* Partial_inplace. */ 310 0x3f, /* Src_mask. */ 311 0x3f, /* Dst_mask. */ 312 TRUE), /* PCrel_offset. */ 313 314 /* An absolute 15 bit relocation, right shifted by 3. */ 315 HOWTO (R_D30V_15, /* Type. */ 316 3, /* Rightshift. */ 317 2, /* Size (0 = byte, 1 = short, 2 = long). */ 318 12, /* Bitsize. */ 319 FALSE, /* PC_relative. */ 320 0, /* Bitpos. */ 321 complain_overflow_signed, /* Complain_on_overflow. */ 322 bfd_elf_generic_reloc, /* Special_function. */ 323 "R_D30V_15", /* Name. */ 324 FALSE, /* Partial_inplace. */ 325 0xfff, /* Src_mask. */ 326 0xfff, /* Dst_mask. */ 327 FALSE), /* PCrel_offset. */ 328 329 /* A relative 15 bit relocation, right shifted by 3. */ 330 HOWTO (R_D30V_15_PCREL, /* Type. */ 331 3, /* Rightshift. */ 332 2, /* Size (0 = byte, 1 = short, 2 = long). */ 333 12, /* Bitsize. */ 334 TRUE, /* PC_relative. */ 335 0, /* Bitpos. */ 336 complain_overflow_signed, /* Complain_on_overflow. */ 337 bfd_elf_d30v_reloc_21, /* Special_function. */ 338 "R_D30V_15_PCREL", /* Name. */ 339 FALSE, /* Partial_inplace. */ 340 0xfff, /* Src_mask. */ 341 0xfff, /* Dst_mask. */ 342 TRUE), /* PCrel_offset. */ 343 344 /* A relative 15 bit relocation, right shifted by 3. */ 345 HOWTO (R_D30V_15_PCREL_R, /* Type. */ 346 3, /* Rightshift. */ 347 2, /* Size (0 = byte, 1 = short, 2 = long). */ 348 12, /* Bitsize. */ 349 TRUE, /* PC_relative. */ 350 0, /* Bitpos. */ 351 complain_overflow_signed, /* Complain_on_overflow. */ 352 bfd_elf_d30v_reloc_21, /* Special_function. */ 353 "R_D30V_15_PCREL_R", /* Name. */ 354 FALSE, /* Partial_inplace. */ 355 0xfff, /* Src_mask. */ 356 0xfff, /* Dst_mask. */ 357 TRUE), /* PCrel_offset. */ 358 359 /* An absolute 21 bit relocation, right shifted by 3. */ 360 HOWTO (R_D30V_21, /* Type. */ 361 3, /* Rightshift. */ 362 2, /* Size (0 = byte, 1 = short, 2 = long). */ 363 18, /* Bitsize. */ 364 FALSE, /* PC_relative. */ 365 0, /* Bitpos. */ 366 complain_overflow_signed, /* Complain_on_overflow. */ 367 bfd_elf_generic_reloc, /* Special_function. */ 368 "R_D30V_21", /* Name. */ 369 FALSE, /* Partial_inplace. */ 370 0x3ffff, /* Src_mask. */ 371 0x3ffff, /* Dst_mask. */ 372 FALSE), /* PCrel_offset. */ 373 374 /* A relative 21 bit relocation, right shifted by 3. */ 375 HOWTO (R_D30V_21_PCREL, /* Type. */ 376 3, /* Rightshift. */ 377 2, /* Size (0 = byte, 1 = short, 2 = long). */ 378 18, /* Bitsize. */ 379 TRUE, /* PC_relative. */ 380 0, /* Bitpos. */ 381 complain_overflow_signed, /* Complain_on_overflow. */ 382 bfd_elf_d30v_reloc_21, /* Special_function. */ 383 "R_D30V_21_PCREL", /* Name. */ 384 FALSE, /* Partial_inplace. */ 385 0x3ffff, /* Src_mask. */ 386 0x3ffff, /* Dst_mask. */ 387 TRUE), /* PCrel_offset. */ 388 389 /* A relative 21 bit relocation, right shifted by 3, in the Right container. */ 390 HOWTO (R_D30V_21_PCREL_R, /* Type. */ 391 3, /* Rightshift. */ 392 2, /* Size (0 = byte, 1 = short, 2 = long). */ 393 18, /* Bitsize. */ 394 TRUE, /* PC_relative. */ 395 0, /* Bitpos. */ 396 complain_overflow_signed, /* Complain_on_overflow. */ 397 bfd_elf_d30v_reloc_21, /* Special_function. */ 398 "R_D30V_21_PCREL_R", /* Name. */ 399 FALSE, /* Partial_inplace. */ 400 0x3ffff, /* Src_mask. */ 401 0x3ffff, /* Dst_mask. */ 402 TRUE), /* PCrel_offset. */ 403 404 /* A D30V 32 bit absolute relocation. */ 405 HOWTO (R_D30V_32, /* Type. */ 406 0, /* Rightshift. */ 407 4, /* Size (0 = byte, 1 = short, 2 = long). */ 408 32, /* Bitsize. */ 409 FALSE, /* PC_relative. */ 410 0, /* Bitpos. */ 411 complain_overflow_bitfield, /* Complain_on_overflow. */ 412 bfd_elf_d30v_reloc, /* Special_function. */ 413 "R_D30V_32", /* Name. */ 414 FALSE, /* Partial_inplace. */ 415 0xffffffff, /* Src_mask. */ 416 0xffffffff, /* Dst_mask. */ 417 FALSE), /* PCrel_offset. */ 418 419 /* A relative 32 bit relocation. */ 420 HOWTO (R_D30V_32_PCREL, /* Type. */ 421 0, /* Rightshift. */ 422 4, /* Size (0 = byte, 1 = short, 2 = long). */ 423 32, /* Bitsize. */ 424 TRUE, /* PC_relative. */ 425 0, /* Bitpos. */ 426 complain_overflow_signed, /* Complain_on_overflow. */ 427 bfd_elf_d30v_reloc, /* Special_function. */ 428 "R_D30V_32_PCREL", /* Name. */ 429 FALSE, /* Partial_inplace. */ 430 0xffffffff, /* Src_mask. */ 431 0xffffffff, /* Dst_mask. */ 432 TRUE), /* PCrel_offset. */ 433 434 /* A regular 32 bit absolute relocation. */ 435 HOWTO (R_D30V_32_NORMAL, /* Type. */ 436 0, /* Rightshift. */ 437 2, /* Size (0 = byte, 1 = short, 2 = long). */ 438 32, /* Bitsize. */ 439 FALSE, /* PC_relative. */ 440 0, /* Bitpos. */ 441 complain_overflow_bitfield, /* Complain_on_overflow. */ 442 bfd_elf_generic_reloc, /* Special_function. */ 443 "R_D30V_32_NORMAL", /* Name. */ 444 FALSE, /* Partial_inplace. */ 445 0xffffffff, /* Src_mask. */ 446 0xffffffff, /* Dst_mask. */ 447 FALSE), /* PCrel_offset. */ 448 449 }; 450 451 /* Map BFD reloc types to D30V ELF reloc types. */ 452 453 struct d30v_reloc_map 454 { 455 bfd_reloc_code_real_type bfd_reloc_val; 456 unsigned char elf_reloc_val; 457 }; 458 459 static const struct d30v_reloc_map d30v_reloc_map[] = 460 { 461 { BFD_RELOC_NONE, R_D30V_NONE, }, 462 { BFD_RELOC_D30V_6, R_D30V_6 }, 463 { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL }, 464 { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R }, 465 { BFD_RELOC_D30V_15, R_D30V_15 }, 466 { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL }, 467 { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R }, 468 { BFD_RELOC_D30V_21, R_D30V_21 }, 469 { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL }, 470 { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R }, 471 { BFD_RELOC_D30V_32, R_D30V_32 }, 472 { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL }, 473 { BFD_RELOC_32, R_D30V_32_NORMAL }, 474 }; 475 476 static reloc_howto_type * 477 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 478 bfd_reloc_code_real_type code) 479 { 480 unsigned int i; 481 482 for (i = 0; 483 i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map); 484 i++) 485 { 486 if (d30v_reloc_map[i].bfd_reloc_val == code) 487 return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val]; 488 } 489 490 return NULL; 491 } 492 493 static reloc_howto_type * 494 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 495 const char *r_name) 496 { 497 unsigned int i; 498 499 for (i = 0; 500 i < sizeof (elf_d30v_howto_table) / sizeof (elf_d30v_howto_table[0]); 501 i++) 502 if (elf_d30v_howto_table[i].name != NULL 503 && strcasecmp (elf_d30v_howto_table[i].name, r_name) == 0) 504 return &elf_d30v_howto_table[i]; 505 506 return NULL; 507 } 508 509 /* Set the howto pointer for an D30V ELF reloc (type REL). */ 510 511 static void 512 d30v_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, 513 arelent *cache_ptr, 514 Elf_Internal_Rela *dst) 515 { 516 unsigned int r_type; 517 518 r_type = ELF32_R_TYPE (dst->r_info); 519 BFD_ASSERT (r_type < (unsigned int) R_D30V_max); 520 cache_ptr->howto = &elf_d30v_howto_table[r_type]; 521 } 522 523 /* Set the howto pointer for an D30V ELF reloc (type RELA). */ 524 525 static void 526 d30v_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, 527 arelent *cache_ptr, 528 Elf_Internal_Rela *dst) 529 { 530 unsigned int r_type; 531 532 r_type = ELF32_R_TYPE (dst->r_info); 533 BFD_ASSERT (r_type < (unsigned int) R_D30V_max); 534 cache_ptr->howto = &elf_d30v_howto_table[r_type]; 535 } 536 537 #define ELF_ARCH bfd_arch_d30v 538 #define ELF_MACHINE_CODE EM_D30V 539 #define ELF_MACHINE_ALT1 EM_CYGNUS_D30V 540 #define ELF_MAXPAGESIZE 0x1000 541 542 #define TARGET_BIG_SYM d30v_elf32_vec 543 #define TARGET_BIG_NAME "elf32-d30v" 544 545 #define elf_info_to_howto d30v_info_to_howto_rela 546 #define elf_info_to_howto_rel d30v_info_to_howto_rel 547 #define elf_backend_object_p 0 548 #define elf_backend_final_write_processing 0 549 550 #include "elf32-target.h" 551