aout-arm.c revision 60484
1/* BFD back-end for raw ARM a.out binaries. 2 Copyright (C) 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc. 3 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org) 4 5This file is part of BFD, the Binary File Descriptor library. 6 7This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or 10(at your option) any later version. 11 12This program is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with this program; if not, write to the Free Software 19Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 20 21 22#define N_TXTADDR(x) \ 23 ((N_MAGIC(x) == NMAGIC) ? 0x8000 : \ 24 (N_MAGIC(x) != ZMAGIC) ? 0 : \ 25 (N_SHARED_LIB(x)) ? ((x).a_entry & ~(TARGET_PAGE_SIZE - 1)) : \ 26 TEXT_START_ADDR) 27 28#define TEXT_START_ADDR 0x8000 29#define TARGET_PAGE_SIZE 0x8000 30#define SEGMENT_SIZE TARGET_PAGE_SIZE 31#define DEFAULT_ARCH bfd_arch_arm 32 33#define MY(OP) CAT(aoutarm_,OP) 34#define N_BADMAG(x) ((((x).a_info & ~007200) != ZMAGIC) && \ 35 (((x).a_info & ~006000) != OMAGIC) && \ 36 ((x).a_info != NMAGIC)) 37#define N_MAGIC(x) ((x).a_info & ~07200) 38 39#include "bfd.h" 40#include "sysdep.h" 41 42#define MYARM(OP) CAT(aoutarm_,OP) 43reloc_howto_type *MYARM(bfd_reloc_type_lookup) 44 PARAMS((bfd *, bfd_reloc_code_real_type)); 45static boolean MYARM(write_object_contents) PARAMS((bfd *)); 46 47/* Avoid multiple defininitions from aoutx if supporting standarad a.out 48 as well as our own. */ 49#define NAME(x,y) CAT3(aoutarm,_32_,y) 50 51#define MY_bfd_reloc_type_lookup aoutarm_bfd_reloc_type_lookup 52 53#include "libaout.h" 54#include "aout/aout64.h" 55 56static bfd_reloc_status_type 57MY(fix_pcrel_26_done) PARAMS ((bfd *, arelent *, asymbol *, PTR, 58 asection *, bfd *, char **)); 59 60static bfd_reloc_status_type 61MY(fix_pcrel_26) PARAMS ((bfd *, arelent *, asymbol *, PTR, 62 asection *, bfd *, char **)); 63static void MY(swap_std_reloc_in) PARAMS ((bfd *, struct reloc_std_external *, 64 arelent *, asymbol **, 65 bfd_size_type)); 66void MY(swap_std_reloc_out) PARAMS ((bfd *, arelent *, 67 struct reloc_std_external *)); 68 69reloc_howto_type MY(howto_table)[] = 70{ 71 /* type rs size bsz pcrel bitpos ovrf sf name part_inpl readmask setmask 72 pcdone */ 73 HOWTO (0, 0, 0, 8, false, 0, complain_overflow_bitfield, 0, "8", true, 74 0x000000ff, 0x000000ff, false), 75 HOWTO (1, 0, 1, 16, false, 0, complain_overflow_bitfield, 0, "16", true, 76 0x0000ffff, 0x0000ffff, false), 77 HOWTO (2, 0, 2, 32, false, 0, complain_overflow_bitfield, 0, "32", true, 78 0xffffffff, 0xffffffff, false), 79 HOWTO (3, 2, 2, 26, true, 0, complain_overflow_signed, MY(fix_pcrel_26), 80 "ARM26", true, 0x00ffffff, 0x00ffffff, true), 81 HOWTO (4, 0, 0, 8, true, 0, complain_overflow_signed, 0, "DISP8", true, 82 0x000000ff, 0x000000ff, true), 83 HOWTO (5, 0, 1, 16, true, 0, complain_overflow_signed, 0, "DISP16", true, 84 0x0000ffff, 0x0000ffff, true), 85 HOWTO (6, 0, 2, 32, true, 0, complain_overflow_signed, 0, "DISP32", true, 86 0xffffffff, 0xffffffff, true), 87 HOWTO (7, 2, 2, 26, false, 0, complain_overflow_signed, 88 MY(fix_pcrel_26_done), "ARM26D", true, 0x0, 0x0, 89 false), 90 EMPTY_HOWTO (-1), 91 HOWTO (9, 0, -1, 16, false, 0, complain_overflow_bitfield, 0, "NEG16", true, 92 0x0000ffff, 0x0000ffff, false), 93 HOWTO (10, 0, -2, 32, false, 0, complain_overflow_bitfield, 0, "NEG32", true, 94 0xffffffff, 0xffffffff, false) 95}; 96 97#define RELOC_ARM_BITS_NEG_BIG ((unsigned int) 0x08) 98#define RELOC_ARM_BITS_NEG_LITTLE ((unsigned int) 0x10) 99 100reloc_howto_type * 101MY(reloc_howto)(abfd, rel, r_index, r_extern, r_pcrel) 102 bfd *abfd; 103 struct reloc_std_external *rel; 104 int *r_index; 105 int *r_extern; 106 int *r_pcrel; 107{ 108 unsigned int r_length; 109 unsigned int r_pcrel_done; 110 unsigned int r_neg; 111 int index; 112 113 *r_pcrel = 0; 114 if (bfd_header_big_endian (abfd)) 115 { 116 *r_index = ((rel->r_index[0] << 16) 117 | (rel->r_index[1] << 8) 118 | rel->r_index[2]); 119 *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG)); 120 r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); 121 r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_BIG)); 122 r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_BIG) 123 >> RELOC_STD_BITS_LENGTH_SH_BIG); 124 } 125 else 126 { 127 *r_index = ((rel->r_index[2] << 16) 128 | (rel->r_index[1] << 8) 129 | rel->r_index[0]); 130 *r_extern = (0 != (rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE)); 131 r_pcrel_done = (0 != (rel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); 132 r_neg = (0 != (rel->r_type[0] & RELOC_ARM_BITS_NEG_LITTLE)); 133 r_length = ((rel->r_type[0] & RELOC_STD_BITS_LENGTH_LITTLE) 134 >> RELOC_STD_BITS_LENGTH_SH_LITTLE); 135 } 136 index = r_length + 4 * r_pcrel_done + 8 * r_neg; 137 if (index == 3) 138 *r_pcrel = 1; 139 140 return MY(howto_table) + index; 141} 142 143#define MY_reloc_howto(BFD, REL, IN, EX, PC) \ 144 MY(reloc_howto) (BFD, REL, &IN, &EX, &PC) 145 146void 147MY(put_reloc)(abfd, r_extern, r_index, value, howto, reloc) 148 bfd *abfd; 149 int r_extern; 150 int r_index; 151 long value; 152 reloc_howto_type *howto; 153 struct reloc_std_external *reloc; 154{ 155 unsigned int r_length; 156 int r_pcrel; 157 int r_neg; 158 159 PUT_WORD (abfd, value, reloc->r_address); 160 r_length = howto->size ; /* Size as a power of two */ 161 162 /* Special case for branch relocations. */ 163 if (howto->type == 3 || howto->type == 7) 164 r_length = 3; 165 166 r_pcrel = howto->type & 4; /* PC Relative done? */ 167 r_neg = howto->type & 8; /* Negative relocation */ 168 if (bfd_header_big_endian (abfd)) 169 { 170 reloc->r_index[0] = r_index >> 16; 171 reloc->r_index[1] = r_index >> 8; 172 reloc->r_index[2] = r_index; 173 reloc->r_type[0] = 174 ((r_extern ? RELOC_STD_BITS_EXTERN_BIG : 0) 175 | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG : 0) 176 | (r_neg ? RELOC_ARM_BITS_NEG_BIG : 0) 177 | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); 178 } 179 else 180 { 181 reloc->r_index[2] = r_index >> 16; 182 reloc->r_index[1] = r_index >> 8; 183 reloc->r_index[0] = r_index; 184 reloc->r_type[0] = 185 ((r_extern ? RELOC_STD_BITS_EXTERN_LITTLE : 0) 186 | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE : 0) 187 | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE : 0) 188 | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); 189 } 190} 191 192#define MY_put_reloc(BFD, EXT, IDX, VAL, HOWTO, RELOC) \ 193 MY(put_reloc)(BFD, EXT, IDX, VAL, HOWTO, RELOC) 194 195void 196MY(relocatable_reloc)(howto, abfd, reloc, amount, r_addr) 197 reloc_howto_type *howto; 198 bfd *abfd; 199 struct reloc_std_external *reloc; 200 bfd_vma *amount; 201 bfd_vma r_addr; 202{ 203 if (howto->type == 3) 204 { 205 if (reloc->r_type[0] 206 & (bfd_header_big_endian (abfd) 207 ? RELOC_STD_BITS_EXTERN_BIG : RELOC_STD_BITS_EXTERN_LITTLE)) 208 { 209 /* The reloc is still external, so don't modify anything. */ 210 *amount = 0; 211 } 212 else 213 { 214 *amount -= r_addr; 215 /* Change the r_pcrel value -- on the ARM, this bit is set once the 216 relocation is done. */ 217 if (bfd_header_big_endian (abfd)) 218 reloc->r_type[0] |= RELOC_STD_BITS_PCREL_BIG; 219 else 220 reloc->r_type[0] |= RELOC_STD_BITS_PCREL_LITTLE; 221 } 222 } 223 else if (howto->type == 7) 224 *amount = 0; 225} 226 227#define MY_relocatable_reloc(HOW, BFD, REL, AMOUNT, ADDR) \ 228 MY(relocatable_reloc)(HOW, BFD, REL, &(AMOUNT), ADDR) 229 230static bfd_reloc_status_type 231MY(fix_pcrel_26_done) (abfd, reloc_entry, symbol, data, input_section, 232 output_bfd, error_message) 233 bfd *abfd ATTRIBUTE_UNUSED; 234 arelent *reloc_entry ATTRIBUTE_UNUSED; 235 asymbol *symbol ATTRIBUTE_UNUSED; 236 PTR data ATTRIBUTE_UNUSED; 237 asection *input_section ATTRIBUTE_UNUSED; 238 bfd *output_bfd ATTRIBUTE_UNUSED; 239 char **error_message ATTRIBUTE_UNUSED; 240{ 241 /* This is dead simple at present. */ 242 return bfd_reloc_ok; 243} 244 245static bfd_reloc_status_type 246MY(fix_pcrel_26) (abfd, reloc_entry, symbol, data, input_section, 247 output_bfd, error_message) 248 bfd *abfd; 249 arelent *reloc_entry; 250 asymbol *symbol; 251 PTR data; 252 asection *input_section; 253 bfd *output_bfd; 254 char **error_message ATTRIBUTE_UNUSED; 255{ 256 bfd_vma relocation; 257 bfd_size_type addr = reloc_entry->address; 258 long target = bfd_get_32 (abfd, (bfd_byte *) data + addr); 259 bfd_reloc_status_type flag = bfd_reloc_ok; 260 261 /* If this is an undefined symbol, return error */ 262 if (symbol->section == &bfd_und_section 263 && (symbol->flags & BSF_WEAK) == 0) 264 return output_bfd ? bfd_reloc_ok : bfd_reloc_undefined; 265 266 /* If the sections are different, and we are doing a partial relocation, 267 just ignore it for now. */ 268 if (symbol->section->name != input_section->name 269 && output_bfd != (bfd *)NULL) 270 return bfd_reloc_ok; 271 272 relocation = (target & 0x00ffffff) << 2; 273 relocation = (relocation ^ 0x02000000) - 0x02000000; /* Sign extend */ 274 relocation += symbol->value; 275 relocation += symbol->section->output_section->vma; 276 relocation += symbol->section->output_offset; 277 relocation += reloc_entry->addend; 278 relocation -= input_section->output_section->vma; 279 relocation -= input_section->output_offset; 280 relocation -= addr; 281 if (relocation & 3) 282 return bfd_reloc_overflow; 283 284 /* Check for overflow */ 285 if (relocation & 0x02000000) 286 { 287 if ((relocation & ~ (bfd_vma) 0x03ffffff) != ~ (bfd_vma) 0x03ffffff) 288 flag = bfd_reloc_overflow; 289 } 290 else if (relocation & ~0x03ffffff) 291 flag = bfd_reloc_overflow; 292 293 target &= ~0x00ffffff; 294 target |= (relocation >> 2) & 0x00ffffff; 295 bfd_put_32 (abfd, target, (bfd_byte *) data + addr); 296 297 /* Now the ARM magic... Change the reloc type so that it is marked as done. 298 Strictly this is only necessary if we are doing a partial relocation. */ 299 reloc_entry->howto = &MY(howto_table)[7]; 300 301 return flag; 302} 303 304reloc_howto_type * 305MY(bfd_reloc_type_lookup)(abfd,code) 306 bfd *abfd; 307 bfd_reloc_code_real_type code; 308{ 309#define ASTD(i,j) case i: return &MY(howto_table)[j] 310 if (code == BFD_RELOC_CTOR) 311 switch (bfd_get_arch_info (abfd)->bits_per_address) 312 { 313 case 32: 314 code = BFD_RELOC_32; 315 break; 316 default: return (CONST struct reloc_howto_struct *) 0; 317 } 318 319 switch (code) 320 { 321 ASTD (BFD_RELOC_16, 1); 322 ASTD (BFD_RELOC_32, 2); 323 ASTD (BFD_RELOC_ARM_PCREL_BRANCH, 3); 324 ASTD (BFD_RELOC_8_PCREL, 4); 325 ASTD (BFD_RELOC_16_PCREL, 5); 326 ASTD (BFD_RELOC_32_PCREL, 6); 327 default: return (CONST struct reloc_howto_struct *) 0; 328 } 329} 330 331#define MY_swap_std_reloc_in MY(swap_std_reloc_in) 332#define MY_swap_std_reloc_out MY(swap_std_reloc_out) 333#define MY_get_section_contents _bfd_generic_get_section_contents 334/* #define MY_bfd_link_hash_table_create _bfd_generic_link_hash_table_create */ 335/* #define MY_bfd_link_add_symbols _bfd_generic_link_add_symbols */ 336/* #define MY_bfd_final_link _bfd_generic_final_link */ 337 338#include "aoutx.h" 339 340static void 341MY_swap_std_reloc_in (abfd, bytes, cache_ptr, symbols, symcount) 342 bfd *abfd; 343 struct reloc_std_external *bytes; 344 arelent *cache_ptr; 345 asymbol **symbols; 346 bfd_size_type symcount ATTRIBUTE_UNUSED; 347{ 348 int r_index; 349 int r_extern; 350 int r_pcrel; 351 struct aoutdata *su = &(abfd->tdata.aout_data->a); 352 353 cache_ptr->address = bfd_h_get_32 (abfd, bytes->r_address); 354 355 cache_ptr->howto = MY_reloc_howto (abfd, bytes, r_index, r_extern, r_pcrel); 356 357 MOVE_ADDRESS (0); 358} 359 360void 361MY_swap_std_reloc_out (abfd, g, natptr) 362 bfd *abfd; 363 arelent *g; 364 struct reloc_std_external *natptr; 365{ 366 int r_index; 367 asymbol *sym = *(g->sym_ptr_ptr); 368 int r_extern; 369 int r_length; 370 int r_pcrel; 371 int r_neg = 0; /* Negative relocs use the BASEREL bit. */ 372 asection *output_section = sym->section->output_section; 373 374 PUT_WORD(abfd, g->address, natptr->r_address); 375 376 r_length = g->howto->size ; /* Size as a power of two */ 377 if (r_length < 0) 378 { 379 r_length = -r_length; 380 r_neg = 1; 381 } 382 383 r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ 384 385 /* For RISC iX, in pc-relative relocs the r_pcrel bit means that the 386 relocation has been done already (Only for the 26-bit one I think)???!!! 387 */ 388 389 if (g->howto->type == 3) 390 { 391 r_length = 3; 392 r_pcrel = 0; 393 } 394 else if (g->howto->type == 7) 395 { 396 r_length = 3; 397 r_pcrel = 1; 398 } 399 400 401#if 0 402 /* For a standard reloc, the addend is in the object file. */ 403 r_addend = g->addend + (*(g->sym_ptr_ptr))->section->output_section->vma; 404#endif 405 406 /* name was clobbered by aout_write_syms to be symbol index */ 407 408 /* If this relocation is relative to a symbol then set the 409 r_index to the symbols index, and the r_extern bit. 410 411 Absolute symbols can come in in two ways, either as an offset 412 from the abs section, or as a symbol which has an abs value. 413 check for that here 414 */ 415 416 if (bfd_is_com_section (output_section) 417 || output_section == &bfd_abs_section 418 || output_section == &bfd_und_section) 419 { 420 if (bfd_abs_section.symbol == sym) 421 { 422 /* Whoops, looked like an abs symbol, but is really an offset 423 from the abs section */ 424 r_index = 0; 425 r_extern = 0; 426 } 427 else 428 { 429 /* Fill in symbol */ 430 r_extern = 1; 431 r_index = (*(g->sym_ptr_ptr))->KEEPIT; 432 } 433 } 434 else 435 { 436 /* Just an ordinary section */ 437 r_extern = 0; 438 r_index = output_section->target_index; 439 } 440 441 /* now the fun stuff */ 442 if (bfd_header_big_endian (abfd)) 443 { 444 natptr->r_index[0] = r_index >> 16; 445 natptr->r_index[1] = r_index >> 8; 446 natptr->r_index[2] = r_index; 447 natptr->r_type[0] = 448 ( (r_extern ? RELOC_STD_BITS_EXTERN_BIG: 0) 449 | (r_pcrel ? RELOC_STD_BITS_PCREL_BIG: 0) 450 | (r_neg ? RELOC_ARM_BITS_NEG_BIG: 0) 451 | (r_length << RELOC_STD_BITS_LENGTH_SH_BIG)); 452 } 453 else 454 { 455 natptr->r_index[2] = r_index >> 16; 456 natptr->r_index[1] = r_index >> 8; 457 natptr->r_index[0] = r_index; 458 natptr->r_type[0] = 459 ( (r_extern ? RELOC_STD_BITS_EXTERN_LITTLE: 0) 460 | (r_pcrel ? RELOC_STD_BITS_PCREL_LITTLE: 0) 461 | (r_neg ? RELOC_ARM_BITS_NEG_LITTLE: 0) 462 | (r_length << RELOC_STD_BITS_LENGTH_SH_LITTLE)); 463 } 464} 465 466#define MY_BFD_TARGET 467 468#include "aout-target.h" 469 470extern const bfd_target aout_arm_big_vec; 471 472const bfd_target aout_arm_little_vec = 473{ 474 "a.out-arm-little", /* name */ 475 bfd_target_aout_flavour, 476 BFD_ENDIAN_LITTLE, /* target byte order (little) */ 477 BFD_ENDIAN_LITTLE, /* target headers byte order (little) */ 478 (HAS_RELOC | EXEC_P | /* object flags */ 479 HAS_LINENO | HAS_DEBUG | 480 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), 481 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 482 MY_symbol_leading_char, 483 AR_PAD_CHAR, /* ar_pad_char */ 484 15, /* ar_max_namelen */ 485 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 486 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 487 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 488 bfd_getl64, bfd_getl_signed_64, bfd_putl64, 489 bfd_getl32, bfd_getl_signed_32, bfd_putl32, 490 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 491 {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ 492 bfd_generic_archive_p, MY_core_file_p}, 493 {bfd_false, MY_mkobject, /* bfd_set_format */ 494 _bfd_generic_mkarchive, bfd_false}, 495 {bfd_false, MY_write_object_contents, /* bfd_write_contents */ 496 _bfd_write_archive_contents, bfd_false}, 497 498 BFD_JUMP_TABLE_GENERIC (MY), 499 BFD_JUMP_TABLE_COPY (MY), 500 BFD_JUMP_TABLE_CORE (MY), 501 BFD_JUMP_TABLE_ARCHIVE (MY), 502 BFD_JUMP_TABLE_SYMBOLS (MY), 503 BFD_JUMP_TABLE_RELOCS (MY), 504 BFD_JUMP_TABLE_WRITE (MY), 505 BFD_JUMP_TABLE_LINK (MY), 506 BFD_JUMP_TABLE_DYNAMIC (MY), 507 508 & aout_arm_big_vec, 509 510 (PTR) MY_backend_data, 511}; 512 513const bfd_target aout_arm_big_vec = 514{ 515 "a.out-arm-big", /* name */ 516 bfd_target_aout_flavour, 517 BFD_ENDIAN_BIG, /* target byte order (big) */ 518 BFD_ENDIAN_BIG, /* target headers byte order (big) */ 519 (HAS_RELOC | EXEC_P | /* object flags */ 520 HAS_LINENO | HAS_DEBUG | 521 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), 522 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 523 MY_symbol_leading_char, 524 AR_PAD_CHAR, /* ar_pad_char */ 525 15, /* ar_max_namelen */ 526 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 527 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 528 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ 529 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 530 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 531 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ 532 {_bfd_dummy_target, MY_object_p, /* bfd_check_format */ 533 bfd_generic_archive_p, MY_core_file_p}, 534 {bfd_false, MY_mkobject, /* bfd_set_format */ 535 _bfd_generic_mkarchive, bfd_false}, 536 {bfd_false, MY_write_object_contents, /* bfd_write_contents */ 537 _bfd_write_archive_contents, bfd_false}, 538 539 BFD_JUMP_TABLE_GENERIC (MY), 540 BFD_JUMP_TABLE_COPY (MY), 541 BFD_JUMP_TABLE_CORE (MY), 542 BFD_JUMP_TABLE_ARCHIVE (MY), 543 BFD_JUMP_TABLE_SYMBOLS (MY), 544 BFD_JUMP_TABLE_RELOCS (MY), 545 BFD_JUMP_TABLE_WRITE (MY), 546 BFD_JUMP_TABLE_LINK (MY), 547 BFD_JUMP_TABLE_DYNAMIC (MY), 548 549 & aout_arm_little_vec, 550 551 (PTR) MY_backend_data, 552}; 553