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