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