1179407Sobrien/* BFD back-end for MIPS Extended-Coff files. 2179407Sobrien Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 3218822Sdim 2000, 2001, 2002, 2003, 2004, 2007 4179407Sobrien Free Software Foundation, Inc. 5179407Sobrien Original version by Per Bothner. 6179407Sobrien Full support added by Ian Lance Taylor, ian@cygnus.com. 7179407Sobrien 8179407SobrienThis file is part of BFD, the Binary File Descriptor library. 9179407Sobrien 10179407SobrienThis program is free software; you can redistribute it and/or modify 11179407Sobrienit under the terms of the GNU General Public License as published by 12179407Sobrienthe Free Software Foundation; either version 2 of the License, or 13179407Sobrien(at your option) any later version. 14179407Sobrien 15179407SobrienThis program is distributed in the hope that it will be useful, 16179407Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 17179407SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18179407SobrienGNU General Public License for more details. 19179407Sobrien 20179407SobrienYou should have received a copy of the GNU General Public License 21179407Sobrienalong with this program; if not, write to the Free Software 22218822SdimFoundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 23179407Sobrien 24218822Sdim#include "sysdep.h" 25179407Sobrien#include "bfd.h" 26179407Sobrien#include "bfdlink.h" 27179407Sobrien#include "libbfd.h" 28179407Sobrien#include "coff/internal.h" 29179407Sobrien#include "coff/sym.h" 30179407Sobrien#include "coff/symconst.h" 31179407Sobrien#include "coff/ecoff.h" 32179407Sobrien#include "coff/mips.h" 33179407Sobrien#include "libcoff.h" 34179407Sobrien#include "libecoff.h" 35179407Sobrien 36179407Sobrien/* Prototypes for static functions. */ 37179407Sobrien 38179407Sobrienstatic bfd_boolean mips_ecoff_bad_format_hook 39179407Sobrien PARAMS ((bfd *abfd, PTR filehdr)); 40179407Sobrienstatic void mips_ecoff_swap_reloc_in 41179407Sobrien PARAMS ((bfd *, PTR, struct internal_reloc *)); 42179407Sobrienstatic void mips_ecoff_swap_reloc_out 43179407Sobrien PARAMS ((bfd *, const struct internal_reloc *, PTR)); 44179407Sobrienstatic void mips_adjust_reloc_in 45179407Sobrien PARAMS ((bfd *, const struct internal_reloc *, arelent *)); 46179407Sobrienstatic void mips_adjust_reloc_out 47179407Sobrien PARAMS ((bfd *, const arelent *, struct internal_reloc *)); 48179407Sobrienstatic bfd_reloc_status_type mips_generic_reloc 49179407Sobrien PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data, 50179407Sobrien asection *section, bfd *output_bfd, char **error)); 51179407Sobrienstatic bfd_reloc_status_type mips_refhi_reloc 52179407Sobrien PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data, 53179407Sobrien asection *section, bfd *output_bfd, char **error)); 54179407Sobrienstatic bfd_reloc_status_type mips_reflo_reloc 55179407Sobrien PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data, 56179407Sobrien asection *section, bfd *output_bfd, char **error)); 57179407Sobrienstatic bfd_reloc_status_type mips_gprel_reloc 58179407Sobrien PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data, 59179407Sobrien asection *section, bfd *output_bfd, char **error)); 60179407Sobrienstatic void mips_relocate_hi 61179407Sobrien PARAMS ((struct internal_reloc *refhi, struct internal_reloc *reflo, 62179407Sobrien bfd *input_bfd, asection *input_section, bfd_byte *contents, 63218822Sdim bfd_vma relocation)); 64179407Sobrienstatic bfd_boolean mips_relocate_section 65179407Sobrien PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PTR)); 66179407Sobrienstatic reloc_howto_type *mips_bfd_reloc_type_lookup 67179407Sobrien PARAMS ((bfd *, bfd_reloc_code_real_type)); 68179407Sobrien 69179407Sobrien/* ECOFF has COFF sections, but the debugging information is stored in 70179407Sobrien a completely different format. ECOFF targets use some of the 71179407Sobrien swapping routines from coffswap.h, and some of the generic COFF 72179407Sobrien routines in coffgen.c, but, unlike the real COFF targets, do not 73179407Sobrien use coffcode.h itself. 74179407Sobrien 75179407Sobrien Get the generic COFF swapping routines, except for the reloc, 76179407Sobrien symbol, and lineno ones. Give them ECOFF names. */ 77179407Sobrien#define MIPSECOFF 78179407Sobrien#define NO_COFF_RELOCS 79179407Sobrien#define NO_COFF_SYMBOLS 80179407Sobrien#define NO_COFF_LINENOS 81179407Sobrien#define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in 82179407Sobrien#define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out 83179407Sobrien#define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in 84179407Sobrien#define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out 85179407Sobrien#define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in 86179407Sobrien#define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out 87179407Sobrien#include "coffswap.h" 88179407Sobrien 89179407Sobrien/* Get the ECOFF swapping routines. */ 90179407Sobrien#define ECOFF_32 91179407Sobrien#include "ecoffswap.h" 92179407Sobrien 93179407Sobrien/* How to process the various relocs types. */ 94179407Sobrien 95179407Sobrienstatic reloc_howto_type mips_howto_table[] = 96179407Sobrien{ 97179407Sobrien /* Reloc type 0 is ignored. The reloc reading code ensures that 98179407Sobrien this is a reference to the .abs section, which will cause 99179407Sobrien bfd_perform_relocation to do nothing. */ 100179407Sobrien HOWTO (MIPS_R_IGNORE, /* type */ 101179407Sobrien 0, /* rightshift */ 102179407Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 103179407Sobrien 8, /* bitsize */ 104179407Sobrien FALSE, /* pc_relative */ 105179407Sobrien 0, /* bitpos */ 106179407Sobrien complain_overflow_dont, /* complain_on_overflow */ 107179407Sobrien 0, /* special_function */ 108179407Sobrien "IGNORE", /* name */ 109179407Sobrien FALSE, /* partial_inplace */ 110179407Sobrien 0, /* src_mask */ 111179407Sobrien 0, /* dst_mask */ 112179407Sobrien FALSE), /* pcrel_offset */ 113179407Sobrien 114179407Sobrien /* A 16 bit reference to a symbol, normally from a data section. */ 115179407Sobrien HOWTO (MIPS_R_REFHALF, /* type */ 116179407Sobrien 0, /* rightshift */ 117179407Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 118179407Sobrien 16, /* bitsize */ 119179407Sobrien FALSE, /* pc_relative */ 120179407Sobrien 0, /* bitpos */ 121179407Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 122179407Sobrien mips_generic_reloc, /* special_function */ 123179407Sobrien "REFHALF", /* name */ 124179407Sobrien TRUE, /* partial_inplace */ 125179407Sobrien 0xffff, /* src_mask */ 126179407Sobrien 0xffff, /* dst_mask */ 127179407Sobrien FALSE), /* pcrel_offset */ 128179407Sobrien 129179407Sobrien /* A 32 bit reference to a symbol, normally from a data section. */ 130179407Sobrien HOWTO (MIPS_R_REFWORD, /* type */ 131179407Sobrien 0, /* rightshift */ 132179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 133179407Sobrien 32, /* bitsize */ 134179407Sobrien FALSE, /* pc_relative */ 135179407Sobrien 0, /* bitpos */ 136179407Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 137179407Sobrien mips_generic_reloc, /* special_function */ 138179407Sobrien "REFWORD", /* name */ 139179407Sobrien TRUE, /* partial_inplace */ 140179407Sobrien 0xffffffff, /* src_mask */ 141179407Sobrien 0xffffffff, /* dst_mask */ 142179407Sobrien FALSE), /* pcrel_offset */ 143179407Sobrien 144179407Sobrien /* A 26 bit absolute jump address. */ 145179407Sobrien HOWTO (MIPS_R_JMPADDR, /* type */ 146179407Sobrien 2, /* rightshift */ 147179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 148179407Sobrien 26, /* bitsize */ 149179407Sobrien FALSE, /* pc_relative */ 150179407Sobrien 0, /* bitpos */ 151179407Sobrien complain_overflow_dont, /* complain_on_overflow */ 152179407Sobrien /* This needs complex overflow 153179407Sobrien detection, because the upper four 154179407Sobrien bits must match the PC. */ 155179407Sobrien mips_generic_reloc, /* special_function */ 156179407Sobrien "JMPADDR", /* name */ 157179407Sobrien TRUE, /* partial_inplace */ 158179407Sobrien 0x3ffffff, /* src_mask */ 159179407Sobrien 0x3ffffff, /* dst_mask */ 160179407Sobrien FALSE), /* pcrel_offset */ 161179407Sobrien 162179407Sobrien /* The high 16 bits of a symbol value. Handled by the function 163179407Sobrien mips_refhi_reloc. */ 164179407Sobrien HOWTO (MIPS_R_REFHI, /* type */ 165179407Sobrien 16, /* rightshift */ 166179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 167179407Sobrien 16, /* bitsize */ 168179407Sobrien FALSE, /* pc_relative */ 169179407Sobrien 0, /* bitpos */ 170179407Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 171179407Sobrien mips_refhi_reloc, /* special_function */ 172179407Sobrien "REFHI", /* name */ 173179407Sobrien TRUE, /* partial_inplace */ 174179407Sobrien 0xffff, /* src_mask */ 175179407Sobrien 0xffff, /* dst_mask */ 176179407Sobrien FALSE), /* pcrel_offset */ 177179407Sobrien 178179407Sobrien /* The low 16 bits of a symbol value. */ 179179407Sobrien HOWTO (MIPS_R_REFLO, /* type */ 180179407Sobrien 0, /* rightshift */ 181179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 182179407Sobrien 16, /* bitsize */ 183179407Sobrien FALSE, /* pc_relative */ 184179407Sobrien 0, /* bitpos */ 185179407Sobrien complain_overflow_dont, /* complain_on_overflow */ 186179407Sobrien mips_reflo_reloc, /* special_function */ 187179407Sobrien "REFLO", /* name */ 188179407Sobrien TRUE, /* partial_inplace */ 189179407Sobrien 0xffff, /* src_mask */ 190179407Sobrien 0xffff, /* dst_mask */ 191179407Sobrien FALSE), /* pcrel_offset */ 192179407Sobrien 193179407Sobrien /* A reference to an offset from the gp register. Handled by the 194179407Sobrien function mips_gprel_reloc. */ 195179407Sobrien HOWTO (MIPS_R_GPREL, /* type */ 196179407Sobrien 0, /* rightshift */ 197179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 198179407Sobrien 16, /* bitsize */ 199179407Sobrien FALSE, /* pc_relative */ 200179407Sobrien 0, /* bitpos */ 201179407Sobrien complain_overflow_signed, /* complain_on_overflow */ 202179407Sobrien mips_gprel_reloc, /* special_function */ 203179407Sobrien "GPREL", /* name */ 204179407Sobrien TRUE, /* partial_inplace */ 205179407Sobrien 0xffff, /* src_mask */ 206179407Sobrien 0xffff, /* dst_mask */ 207179407Sobrien FALSE), /* pcrel_offset */ 208179407Sobrien 209179407Sobrien /* A reference to a literal using an offset from the gp register. 210179407Sobrien Handled by the function mips_gprel_reloc. */ 211179407Sobrien HOWTO (MIPS_R_LITERAL, /* type */ 212179407Sobrien 0, /* rightshift */ 213179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 214179407Sobrien 16, /* bitsize */ 215179407Sobrien FALSE, /* pc_relative */ 216179407Sobrien 0, /* bitpos */ 217179407Sobrien complain_overflow_signed, /* complain_on_overflow */ 218179407Sobrien mips_gprel_reloc, /* special_function */ 219179407Sobrien "LITERAL", /* name */ 220179407Sobrien TRUE, /* partial_inplace */ 221179407Sobrien 0xffff, /* src_mask */ 222179407Sobrien 0xffff, /* dst_mask */ 223179407Sobrien FALSE), /* pcrel_offset */ 224179407Sobrien 225179407Sobrien EMPTY_HOWTO (8), 226179407Sobrien EMPTY_HOWTO (9), 227179407Sobrien EMPTY_HOWTO (10), 228179407Sobrien EMPTY_HOWTO (11), 229179407Sobrien 230218822Sdim /* FIXME: This relocation is used (internally only) to represent branches 231218822Sdim when assembling. It should never appear in output files, and 232218822Sdim be removed. (It used to be used for embedded-PIC support.) */ 233179407Sobrien HOWTO (MIPS_R_PCREL16, /* type */ 234179407Sobrien 2, /* rightshift */ 235179407Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 236179407Sobrien 16, /* bitsize */ 237179407Sobrien TRUE, /* pc_relative */ 238179407Sobrien 0, /* bitpos */ 239179407Sobrien complain_overflow_signed, /* complain_on_overflow */ 240179407Sobrien mips_generic_reloc, /* special_function */ 241179407Sobrien "PCREL16", /* name */ 242179407Sobrien TRUE, /* partial_inplace */ 243179407Sobrien 0xffff, /* src_mask */ 244179407Sobrien 0xffff, /* dst_mask */ 245179407Sobrien TRUE), /* pcrel_offset */ 246179407Sobrien}; 247179407Sobrien 248179407Sobrien#define MIPS_HOWTO_COUNT \ 249179407Sobrien (sizeof mips_howto_table / sizeof mips_howto_table[0]) 250179407Sobrien 251179407Sobrien/* See whether the magic number matches. */ 252179407Sobrien 253179407Sobrienstatic bfd_boolean 254179407Sobrienmips_ecoff_bad_format_hook (abfd, filehdr) 255179407Sobrien bfd *abfd; 256179407Sobrien PTR filehdr; 257179407Sobrien{ 258179407Sobrien struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr; 259179407Sobrien 260179407Sobrien switch (internal_f->f_magic) 261179407Sobrien { 262179407Sobrien case MIPS_MAGIC_1: 263179407Sobrien /* I don't know what endianness this implies. */ 264179407Sobrien return TRUE; 265179407Sobrien 266179407Sobrien case MIPS_MAGIC_BIG: 267179407Sobrien case MIPS_MAGIC_BIG2: 268179407Sobrien case MIPS_MAGIC_BIG3: 269179407Sobrien return bfd_big_endian (abfd); 270179407Sobrien 271179407Sobrien case MIPS_MAGIC_LITTLE: 272179407Sobrien case MIPS_MAGIC_LITTLE2: 273179407Sobrien case MIPS_MAGIC_LITTLE3: 274179407Sobrien return bfd_little_endian (abfd); 275179407Sobrien 276179407Sobrien default: 277179407Sobrien return FALSE; 278179407Sobrien } 279179407Sobrien} 280179407Sobrien 281179407Sobrien/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in 282179407Sobrien external form. They use a bit which indicates whether the symbol 283179407Sobrien is external. */ 284179407Sobrien 285179407Sobrien/* Swap a reloc in. */ 286179407Sobrien 287179407Sobrienstatic void 288179407Sobrienmips_ecoff_swap_reloc_in (abfd, ext_ptr, intern) 289179407Sobrien bfd *abfd; 290179407Sobrien PTR ext_ptr; 291179407Sobrien struct internal_reloc *intern; 292179407Sobrien{ 293179407Sobrien const RELOC *ext = (RELOC *) ext_ptr; 294179407Sobrien 295179407Sobrien intern->r_vaddr = H_GET_32 (abfd, ext->r_vaddr); 296179407Sobrien if (bfd_header_big_endian (abfd)) 297179407Sobrien { 298179407Sobrien intern->r_symndx = (((int) ext->r_bits[0] 299179407Sobrien << RELOC_BITS0_SYMNDX_SH_LEFT_BIG) 300179407Sobrien | ((int) ext->r_bits[1] 301179407Sobrien << RELOC_BITS1_SYMNDX_SH_LEFT_BIG) 302179407Sobrien | ((int) ext->r_bits[2] 303179407Sobrien << RELOC_BITS2_SYMNDX_SH_LEFT_BIG)); 304179407Sobrien intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG) 305179407Sobrien >> RELOC_BITS3_TYPE_SH_BIG); 306179407Sobrien intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0; 307179407Sobrien } 308179407Sobrien else 309179407Sobrien { 310179407Sobrien intern->r_symndx = (((int) ext->r_bits[0] 311179407Sobrien << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE) 312179407Sobrien | ((int) ext->r_bits[1] 313179407Sobrien << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE) 314179407Sobrien | ((int) ext->r_bits[2] 315179407Sobrien << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE)); 316179407Sobrien intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE) 317179407Sobrien >> RELOC_BITS3_TYPE_SH_LITTLE) 318179407Sobrien | ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE) 319179407Sobrien << RELOC_BITS3_TYPEHI_SH_LITTLE)); 320179407Sobrien intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0; 321179407Sobrien } 322179407Sobrien} 323179407Sobrien 324179407Sobrien/* Swap a reloc out. */ 325179407Sobrien 326179407Sobrienstatic void 327179407Sobrienmips_ecoff_swap_reloc_out (abfd, intern, dst) 328179407Sobrien bfd *abfd; 329179407Sobrien const struct internal_reloc *intern; 330179407Sobrien PTR dst; 331179407Sobrien{ 332179407Sobrien RELOC *ext = (RELOC *) dst; 333179407Sobrien long r_symndx; 334179407Sobrien 335179407Sobrien BFD_ASSERT (intern->r_extern 336179407Sobrien || (intern->r_symndx >= 0 && intern->r_symndx <= 12)); 337179407Sobrien 338218822Sdim r_symndx = intern->r_symndx; 339179407Sobrien 340179407Sobrien H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr); 341179407Sobrien if (bfd_header_big_endian (abfd)) 342179407Sobrien { 343179407Sobrien ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG; 344179407Sobrien ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG; 345179407Sobrien ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG; 346179407Sobrien ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG) 347179407Sobrien & RELOC_BITS3_TYPE_BIG) 348179407Sobrien | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0)); 349179407Sobrien } 350179407Sobrien else 351179407Sobrien { 352179407Sobrien ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE; 353179407Sobrien ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE; 354179407Sobrien ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE; 355179407Sobrien ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE) 356179407Sobrien & RELOC_BITS3_TYPE_LITTLE) 357179407Sobrien | ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE 358179407Sobrien & RELOC_BITS3_TYPEHI_LITTLE)) 359179407Sobrien | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0)); 360179407Sobrien } 361179407Sobrien} 362179407Sobrien 363179407Sobrien/* Finish canonicalizing a reloc. Part of this is generic to all 364179407Sobrien ECOFF targets, and that part is in ecoff.c. The rest is done in 365179407Sobrien this backend routine. It must fill in the howto field. */ 366179407Sobrien 367179407Sobrienstatic void 368179407Sobrienmips_adjust_reloc_in (abfd, intern, rptr) 369179407Sobrien bfd *abfd; 370179407Sobrien const struct internal_reloc *intern; 371179407Sobrien arelent *rptr; 372179407Sobrien{ 373218822Sdim if (intern->r_type > MIPS_R_PCREL16) 374179407Sobrien abort (); 375179407Sobrien 376179407Sobrien if (! intern->r_extern 377179407Sobrien && (intern->r_type == MIPS_R_GPREL 378179407Sobrien || intern->r_type == MIPS_R_LITERAL)) 379179407Sobrien rptr->addend += ecoff_data (abfd)->gp; 380179407Sobrien 381179407Sobrien /* If the type is MIPS_R_IGNORE, make sure this is a reference to 382179407Sobrien the absolute section so that the reloc is ignored. */ 383179407Sobrien if (intern->r_type == MIPS_R_IGNORE) 384179407Sobrien rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; 385179407Sobrien 386179407Sobrien rptr->howto = &mips_howto_table[intern->r_type]; 387179407Sobrien} 388179407Sobrien 389179407Sobrien/* Make any adjustments needed to a reloc before writing it out. None 390179407Sobrien are needed for MIPS. */ 391179407Sobrien 392179407Sobrienstatic void 393179407Sobrienmips_adjust_reloc_out (abfd, rel, intern) 394179407Sobrien bfd *abfd ATTRIBUTE_UNUSED; 395218822Sdim const arelent *rel ATTRIBUTE_UNUSED; 396218822Sdim struct internal_reloc *intern ATTRIBUTE_UNUSED; 397179407Sobrien{ 398179407Sobrien} 399179407Sobrien 400179407Sobrien/* ECOFF relocs are either against external symbols, or against 401179407Sobrien sections. If we are producing relocatable output, and the reloc 402179407Sobrien is against an external symbol, and nothing has given us any 403179407Sobrien additional addend, the resulting reloc will also be against the 404179407Sobrien same symbol. In such a case, we don't want to change anything 405179407Sobrien about the way the reloc is handled, since it will all be done at 406179407Sobrien final link time. Rather than put special case code into 407179407Sobrien bfd_perform_relocation, all the reloc types use this howto 408179407Sobrien function. It just short circuits the reloc if producing 409179407Sobrien relocatable output against an external symbol. */ 410179407Sobrien 411179407Sobrienstatic bfd_reloc_status_type 412179407Sobrienmips_generic_reloc (abfd, 413179407Sobrien reloc_entry, 414179407Sobrien symbol, 415179407Sobrien data, 416179407Sobrien input_section, 417179407Sobrien output_bfd, 418179407Sobrien error_message) 419179407Sobrien bfd *abfd ATTRIBUTE_UNUSED; 420179407Sobrien arelent *reloc_entry; 421179407Sobrien asymbol *symbol; 422179407Sobrien PTR data ATTRIBUTE_UNUSED; 423179407Sobrien asection *input_section; 424179407Sobrien bfd *output_bfd; 425179407Sobrien char **error_message ATTRIBUTE_UNUSED; 426179407Sobrien{ 427179407Sobrien if (output_bfd != (bfd *) NULL 428179407Sobrien && (symbol->flags & BSF_SECTION_SYM) == 0 429179407Sobrien && reloc_entry->addend == 0) 430179407Sobrien { 431179407Sobrien reloc_entry->address += input_section->output_offset; 432179407Sobrien return bfd_reloc_ok; 433179407Sobrien } 434179407Sobrien 435179407Sobrien return bfd_reloc_continue; 436179407Sobrien} 437179407Sobrien 438179407Sobrien/* Do a REFHI relocation. This has to be done in combination with a 439179407Sobrien REFLO reloc, because there is a carry from the REFLO to the REFHI. 440179407Sobrien Here we just save the information we need; we do the actual 441179407Sobrien relocation when we see the REFLO. MIPS ECOFF requires that the 442179407Sobrien REFLO immediately follow the REFHI. As a GNU extension, we permit 443179407Sobrien an arbitrary number of HI relocs to be associated with a single LO 444179407Sobrien reloc. This extension permits gcc to output the HI and LO relocs 445179407Sobrien itself. */ 446179407Sobrien 447179407Sobrienstruct mips_hi 448179407Sobrien{ 449179407Sobrien struct mips_hi *next; 450179407Sobrien bfd_byte *addr; 451179407Sobrien bfd_vma addend; 452179407Sobrien}; 453179407Sobrien 454179407Sobrien/* FIXME: This should not be a static variable. */ 455179407Sobrien 456179407Sobrienstatic struct mips_hi *mips_refhi_list; 457179407Sobrien 458179407Sobrienstatic bfd_reloc_status_type 459179407Sobrienmips_refhi_reloc (abfd, 460179407Sobrien reloc_entry, 461179407Sobrien symbol, 462179407Sobrien data, 463179407Sobrien input_section, 464179407Sobrien output_bfd, 465179407Sobrien error_message) 466179407Sobrien bfd *abfd ATTRIBUTE_UNUSED; 467179407Sobrien arelent *reloc_entry; 468179407Sobrien asymbol *symbol; 469179407Sobrien PTR data; 470179407Sobrien asection *input_section; 471179407Sobrien bfd *output_bfd; 472179407Sobrien char **error_message ATTRIBUTE_UNUSED; 473179407Sobrien{ 474179407Sobrien bfd_reloc_status_type ret; 475179407Sobrien bfd_vma relocation; 476179407Sobrien struct mips_hi *n; 477179407Sobrien 478179407Sobrien /* If we're relocating, and this an external symbol, we don't want 479179407Sobrien to change anything. */ 480179407Sobrien if (output_bfd != (bfd *) NULL 481179407Sobrien && (symbol->flags & BSF_SECTION_SYM) == 0 482179407Sobrien && reloc_entry->addend == 0) 483179407Sobrien { 484179407Sobrien reloc_entry->address += input_section->output_offset; 485179407Sobrien return bfd_reloc_ok; 486179407Sobrien } 487179407Sobrien 488179407Sobrien ret = bfd_reloc_ok; 489179407Sobrien if (bfd_is_und_section (symbol->section) 490179407Sobrien && output_bfd == (bfd *) NULL) 491179407Sobrien ret = bfd_reloc_undefined; 492179407Sobrien 493179407Sobrien if (bfd_is_com_section (symbol->section)) 494179407Sobrien relocation = 0; 495179407Sobrien else 496179407Sobrien relocation = symbol->value; 497179407Sobrien 498179407Sobrien relocation += symbol->section->output_section->vma; 499179407Sobrien relocation += symbol->section->output_offset; 500179407Sobrien relocation += reloc_entry->addend; 501179407Sobrien 502218822Sdim if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 503179407Sobrien return bfd_reloc_outofrange; 504179407Sobrien 505179407Sobrien /* Save the information, and let REFLO do the actual relocation. */ 506179407Sobrien n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n); 507179407Sobrien if (n == NULL) 508179407Sobrien return bfd_reloc_outofrange; 509179407Sobrien n->addr = (bfd_byte *) data + reloc_entry->address; 510179407Sobrien n->addend = relocation; 511179407Sobrien n->next = mips_refhi_list; 512179407Sobrien mips_refhi_list = n; 513179407Sobrien 514179407Sobrien if (output_bfd != (bfd *) NULL) 515179407Sobrien reloc_entry->address += input_section->output_offset; 516179407Sobrien 517179407Sobrien return ret; 518179407Sobrien} 519179407Sobrien 520179407Sobrien/* Do a REFLO relocation. This is a straightforward 16 bit inplace 521179407Sobrien relocation; this function exists in order to do the REFHI 522179407Sobrien relocation described above. */ 523179407Sobrien 524179407Sobrienstatic bfd_reloc_status_type 525179407Sobrienmips_reflo_reloc (abfd, 526179407Sobrien reloc_entry, 527179407Sobrien symbol, 528179407Sobrien data, 529179407Sobrien input_section, 530179407Sobrien output_bfd, 531179407Sobrien error_message) 532179407Sobrien bfd *abfd; 533179407Sobrien arelent *reloc_entry; 534179407Sobrien asymbol *symbol; 535179407Sobrien PTR data; 536179407Sobrien asection *input_section; 537179407Sobrien bfd *output_bfd; 538179407Sobrien char **error_message; 539179407Sobrien{ 540179407Sobrien if (mips_refhi_list != NULL) 541179407Sobrien { 542179407Sobrien struct mips_hi *l; 543179407Sobrien 544179407Sobrien l = mips_refhi_list; 545179407Sobrien while (l != NULL) 546179407Sobrien { 547179407Sobrien unsigned long insn; 548179407Sobrien unsigned long val; 549179407Sobrien unsigned long vallo; 550179407Sobrien struct mips_hi *next; 551179407Sobrien 552179407Sobrien /* Do the REFHI relocation. Note that we actually don't 553179407Sobrien need to know anything about the REFLO itself, except 554179407Sobrien where to find the low 16 bits of the addend needed by the 555179407Sobrien REFHI. */ 556179407Sobrien insn = bfd_get_32 (abfd, l->addr); 557179407Sobrien vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) 558179407Sobrien & 0xffff); 559179407Sobrien val = ((insn & 0xffff) << 16) + vallo; 560179407Sobrien val += l->addend; 561179407Sobrien 562179407Sobrien /* The low order 16 bits are always treated as a signed 563179407Sobrien value. Therefore, a negative value in the low order bits 564179407Sobrien requires an adjustment in the high order bits. We need 565179407Sobrien to make this adjustment in two ways: once for the bits we 566179407Sobrien took from the data, and once for the bits we are putting 567179407Sobrien back in to the data. */ 568179407Sobrien if ((vallo & 0x8000) != 0) 569179407Sobrien val -= 0x10000; 570179407Sobrien if ((val & 0x8000) != 0) 571179407Sobrien val += 0x10000; 572179407Sobrien 573179407Sobrien insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff); 574179407Sobrien bfd_put_32 (abfd, (bfd_vma) insn, l->addr); 575179407Sobrien 576179407Sobrien next = l->next; 577179407Sobrien free (l); 578179407Sobrien l = next; 579179407Sobrien } 580179407Sobrien 581179407Sobrien mips_refhi_list = NULL; 582179407Sobrien } 583179407Sobrien 584179407Sobrien /* Now do the REFLO reloc in the usual way. */ 585179407Sobrien return mips_generic_reloc (abfd, reloc_entry, symbol, data, 586179407Sobrien input_section, output_bfd, error_message); 587179407Sobrien} 588179407Sobrien 589179407Sobrien/* Do a GPREL relocation. This is a 16 bit value which must become 590179407Sobrien the offset from the gp register. */ 591179407Sobrien 592179407Sobrienstatic bfd_reloc_status_type 593179407Sobrienmips_gprel_reloc (abfd, 594179407Sobrien reloc_entry, 595179407Sobrien symbol, 596179407Sobrien data, 597179407Sobrien input_section, 598179407Sobrien output_bfd, 599179407Sobrien error_message) 600179407Sobrien bfd *abfd; 601179407Sobrien arelent *reloc_entry; 602179407Sobrien asymbol *symbol; 603179407Sobrien PTR data; 604179407Sobrien asection *input_section; 605179407Sobrien bfd *output_bfd; 606179407Sobrien char **error_message; 607179407Sobrien{ 608179407Sobrien bfd_boolean relocatable; 609179407Sobrien bfd_vma gp; 610179407Sobrien bfd_vma relocation; 611179407Sobrien unsigned long val; 612179407Sobrien unsigned long insn; 613179407Sobrien 614179407Sobrien /* If we're relocating, and this is an external symbol with no 615179407Sobrien addend, we don't want to change anything. We will only have an 616179407Sobrien addend if this is a newly created reloc, not read from an ECOFF 617179407Sobrien file. */ 618179407Sobrien if (output_bfd != (bfd *) NULL 619179407Sobrien && (symbol->flags & BSF_SECTION_SYM) == 0 620179407Sobrien && reloc_entry->addend == 0) 621179407Sobrien { 622179407Sobrien reloc_entry->address += input_section->output_offset; 623179407Sobrien return bfd_reloc_ok; 624179407Sobrien } 625179407Sobrien 626179407Sobrien if (output_bfd != (bfd *) NULL) 627179407Sobrien relocatable = TRUE; 628179407Sobrien else 629179407Sobrien { 630179407Sobrien relocatable = FALSE; 631179407Sobrien output_bfd = symbol->section->output_section->owner; 632179407Sobrien } 633179407Sobrien 634179407Sobrien if (bfd_is_und_section (symbol->section) && ! relocatable) 635179407Sobrien return bfd_reloc_undefined; 636179407Sobrien 637179407Sobrien /* We have to figure out the gp value, so that we can adjust the 638179407Sobrien symbol value correctly. We look up the symbol _gp in the output 639179407Sobrien BFD. If we can't find it, we're stuck. We cache it in the ECOFF 640179407Sobrien target data. We don't need to adjust the symbol value for an 641179407Sobrien external symbol if we are producing relocatable output. */ 642179407Sobrien gp = _bfd_get_gp_value (output_bfd); 643179407Sobrien if (gp == 0 644179407Sobrien && (! relocatable 645179407Sobrien || (symbol->flags & BSF_SECTION_SYM) != 0)) 646179407Sobrien { 647179407Sobrien if (relocatable) 648179407Sobrien { 649179407Sobrien /* Make up a value. */ 650179407Sobrien gp = symbol->section->output_section->vma + 0x4000; 651179407Sobrien _bfd_set_gp_value (output_bfd, gp); 652179407Sobrien } 653179407Sobrien else 654179407Sobrien { 655179407Sobrien unsigned int count; 656179407Sobrien asymbol **sym; 657179407Sobrien unsigned int i; 658179407Sobrien 659179407Sobrien count = bfd_get_symcount (output_bfd); 660179407Sobrien sym = bfd_get_outsymbols (output_bfd); 661179407Sobrien 662179407Sobrien if (sym == (asymbol **) NULL) 663179407Sobrien i = count; 664179407Sobrien else 665179407Sobrien { 666179407Sobrien for (i = 0; i < count; i++, sym++) 667179407Sobrien { 668179407Sobrien register const char *name; 669179407Sobrien 670179407Sobrien name = bfd_asymbol_name (*sym); 671179407Sobrien if (*name == '_' && strcmp (name, "_gp") == 0) 672179407Sobrien { 673179407Sobrien gp = bfd_asymbol_value (*sym); 674179407Sobrien _bfd_set_gp_value (output_bfd, gp); 675179407Sobrien break; 676179407Sobrien } 677179407Sobrien } 678179407Sobrien } 679179407Sobrien 680179407Sobrien if (i >= count) 681179407Sobrien { 682179407Sobrien /* Only get the error once. */ 683179407Sobrien gp = 4; 684179407Sobrien _bfd_set_gp_value (output_bfd, gp); 685179407Sobrien *error_message = 686179407Sobrien (char *) _("GP relative relocation when _gp not defined"); 687179407Sobrien return bfd_reloc_dangerous; 688179407Sobrien } 689179407Sobrien } 690179407Sobrien } 691179407Sobrien 692179407Sobrien if (bfd_is_com_section (symbol->section)) 693179407Sobrien relocation = 0; 694179407Sobrien else 695179407Sobrien relocation = symbol->value; 696179407Sobrien 697179407Sobrien relocation += symbol->section->output_section->vma; 698179407Sobrien relocation += symbol->section->output_offset; 699179407Sobrien 700218822Sdim if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 701179407Sobrien return bfd_reloc_outofrange; 702179407Sobrien 703179407Sobrien insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); 704179407Sobrien 705179407Sobrien /* Set val to the offset into the section or symbol. */ 706179407Sobrien val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; 707179407Sobrien if (val & 0x8000) 708179407Sobrien val -= 0x10000; 709179407Sobrien 710179407Sobrien /* Adjust val for the final section location and GP value. If we 711179407Sobrien are producing relocatable output, we don't want to do this for 712179407Sobrien an external symbol. */ 713179407Sobrien if (! relocatable 714179407Sobrien || (symbol->flags & BSF_SECTION_SYM) != 0) 715179407Sobrien val += relocation - gp; 716179407Sobrien 717179407Sobrien insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff); 718179407Sobrien bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address); 719179407Sobrien 720179407Sobrien if (relocatable) 721179407Sobrien reloc_entry->address += input_section->output_offset; 722179407Sobrien 723179407Sobrien /* Make sure it fit in 16 bits. */ 724179407Sobrien if ((long) val >= 0x8000 || (long) val < -0x8000) 725179407Sobrien return bfd_reloc_overflow; 726179407Sobrien 727179407Sobrien return bfd_reloc_ok; 728179407Sobrien} 729179407Sobrien 730179407Sobrien/* Get the howto structure for a generic reloc type. */ 731179407Sobrien 732179407Sobrienstatic reloc_howto_type * 733179407Sobrienmips_bfd_reloc_type_lookup (abfd, code) 734179407Sobrien bfd *abfd ATTRIBUTE_UNUSED; 735179407Sobrien bfd_reloc_code_real_type code; 736179407Sobrien{ 737179407Sobrien int mips_type; 738179407Sobrien 739179407Sobrien switch (code) 740179407Sobrien { 741179407Sobrien case BFD_RELOC_16: 742179407Sobrien mips_type = MIPS_R_REFHALF; 743179407Sobrien break; 744179407Sobrien case BFD_RELOC_32: 745179407Sobrien case BFD_RELOC_CTOR: 746179407Sobrien mips_type = MIPS_R_REFWORD; 747179407Sobrien break; 748179407Sobrien case BFD_RELOC_MIPS_JMP: 749179407Sobrien mips_type = MIPS_R_JMPADDR; 750179407Sobrien break; 751179407Sobrien case BFD_RELOC_HI16_S: 752179407Sobrien mips_type = MIPS_R_REFHI; 753179407Sobrien break; 754179407Sobrien case BFD_RELOC_LO16: 755179407Sobrien mips_type = MIPS_R_REFLO; 756179407Sobrien break; 757179407Sobrien case BFD_RELOC_GPREL16: 758179407Sobrien mips_type = MIPS_R_GPREL; 759179407Sobrien break; 760179407Sobrien case BFD_RELOC_MIPS_LITERAL: 761179407Sobrien mips_type = MIPS_R_LITERAL; 762179407Sobrien break; 763179407Sobrien case BFD_RELOC_16_PCREL_S2: 764179407Sobrien mips_type = MIPS_R_PCREL16; 765179407Sobrien break; 766179407Sobrien default: 767179407Sobrien return (reloc_howto_type *) NULL; 768179407Sobrien } 769179407Sobrien 770179407Sobrien return &mips_howto_table[mips_type]; 771179407Sobrien} 772218822Sdim 773218822Sdimstatic reloc_howto_type * 774218822Sdimmips_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 775218822Sdim const char *r_name) 776218822Sdim{ 777218822Sdim unsigned int i; 778218822Sdim 779218822Sdim for (i = 0; 780218822Sdim i < sizeof (mips_howto_table) / sizeof (mips_howto_table[0]); 781218822Sdim i++) 782218822Sdim if (mips_howto_table[i].name != NULL 783218822Sdim && strcasecmp (mips_howto_table[i].name, r_name) == 0) 784218822Sdim return &mips_howto_table[i]; 785218822Sdim 786218822Sdim return NULL; 787218822Sdim} 788179407Sobrien 789179407Sobrien/* A helper routine for mips_relocate_section which handles the REFHI 790218822Sdim relocations. The REFHI relocation must be followed by a REFLO 791218822Sdim relocation, and the addend used is formed from the addends of both 792218822Sdim instructions. */ 793179407Sobrien 794179407Sobrienstatic void 795218822Sdimmips_relocate_hi (refhi, reflo, input_bfd, input_section, contents, 796218822Sdim relocation) 797179407Sobrien struct internal_reloc *refhi; 798179407Sobrien struct internal_reloc *reflo; 799179407Sobrien bfd *input_bfd; 800179407Sobrien asection *input_section; 801179407Sobrien bfd_byte *contents; 802179407Sobrien bfd_vma relocation; 803179407Sobrien{ 804179407Sobrien unsigned long insn; 805179407Sobrien unsigned long val; 806179407Sobrien unsigned long vallo; 807179407Sobrien 808179407Sobrien if (refhi == NULL) 809179407Sobrien return; 810179407Sobrien 811179407Sobrien insn = bfd_get_32 (input_bfd, 812218822Sdim contents + refhi->r_vaddr - input_section->vma); 813179407Sobrien if (reflo == NULL) 814179407Sobrien vallo = 0; 815179407Sobrien else 816179407Sobrien vallo = (bfd_get_32 (input_bfd, 817218822Sdim contents + reflo->r_vaddr - input_section->vma) 818179407Sobrien & 0xffff); 819179407Sobrien 820179407Sobrien val = ((insn & 0xffff) << 16) + vallo; 821179407Sobrien val += relocation; 822179407Sobrien 823179407Sobrien /* The low order 16 bits are always treated as a signed value. 824179407Sobrien Therefore, a negative value in the low order bits requires an 825179407Sobrien adjustment in the high order bits. We need to make this 826179407Sobrien adjustment in two ways: once for the bits we took from the data, 827179407Sobrien and once for the bits we are putting back in to the data. */ 828179407Sobrien if ((vallo & 0x8000) != 0) 829179407Sobrien val -= 0x10000; 830179407Sobrien 831179407Sobrien if ((val & 0x8000) != 0) 832179407Sobrien val += 0x10000; 833179407Sobrien 834179407Sobrien insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff); 835179407Sobrien bfd_put_32 (input_bfd, (bfd_vma) insn, 836218822Sdim contents + refhi->r_vaddr - input_section->vma); 837179407Sobrien} 838179407Sobrien 839179407Sobrien/* Relocate a section while linking a MIPS ECOFF file. */ 840179407Sobrien 841179407Sobrienstatic bfd_boolean 842179407Sobrienmips_relocate_section (output_bfd, info, input_bfd, input_section, 843179407Sobrien contents, external_relocs) 844179407Sobrien bfd *output_bfd; 845179407Sobrien struct bfd_link_info *info; 846179407Sobrien bfd *input_bfd; 847179407Sobrien asection *input_section; 848179407Sobrien bfd_byte *contents; 849179407Sobrien PTR external_relocs; 850179407Sobrien{ 851179407Sobrien asection **symndx_to_section; 852179407Sobrien struct ecoff_link_hash_entry **sym_hashes; 853179407Sobrien bfd_vma gp; 854179407Sobrien bfd_boolean gp_undefined; 855179407Sobrien struct external_reloc *ext_rel; 856179407Sobrien struct external_reloc *ext_rel_end; 857179407Sobrien unsigned int i; 858179407Sobrien bfd_boolean got_lo; 859179407Sobrien struct internal_reloc lo_int_rel; 860179407Sobrien bfd_size_type amt; 861179407Sobrien 862179407Sobrien BFD_ASSERT (input_bfd->xvec->byteorder 863179407Sobrien == output_bfd->xvec->byteorder); 864179407Sobrien 865179407Sobrien /* We keep a table mapping the symndx found in an internal reloc to 866179407Sobrien the appropriate section. This is faster than looking up the 867179407Sobrien section by name each time. */ 868179407Sobrien symndx_to_section = ecoff_data (input_bfd)->symndx_to_section; 869179407Sobrien if (symndx_to_section == (asection **) NULL) 870179407Sobrien { 871179407Sobrien amt = NUM_RELOC_SECTIONS * sizeof (asection *); 872179407Sobrien symndx_to_section = (asection **) bfd_alloc (input_bfd, amt); 873179407Sobrien if (!symndx_to_section) 874179407Sobrien return FALSE; 875179407Sobrien 876179407Sobrien symndx_to_section[RELOC_SECTION_NONE] = NULL; 877179407Sobrien symndx_to_section[RELOC_SECTION_TEXT] = 878179407Sobrien bfd_get_section_by_name (input_bfd, ".text"); 879179407Sobrien symndx_to_section[RELOC_SECTION_RDATA] = 880179407Sobrien bfd_get_section_by_name (input_bfd, ".rdata"); 881179407Sobrien symndx_to_section[RELOC_SECTION_DATA] = 882179407Sobrien bfd_get_section_by_name (input_bfd, ".data"); 883179407Sobrien symndx_to_section[RELOC_SECTION_SDATA] = 884179407Sobrien bfd_get_section_by_name (input_bfd, ".sdata"); 885179407Sobrien symndx_to_section[RELOC_SECTION_SBSS] = 886179407Sobrien bfd_get_section_by_name (input_bfd, ".sbss"); 887179407Sobrien symndx_to_section[RELOC_SECTION_BSS] = 888179407Sobrien bfd_get_section_by_name (input_bfd, ".bss"); 889179407Sobrien symndx_to_section[RELOC_SECTION_INIT] = 890179407Sobrien bfd_get_section_by_name (input_bfd, ".init"); 891179407Sobrien symndx_to_section[RELOC_SECTION_LIT8] = 892179407Sobrien bfd_get_section_by_name (input_bfd, ".lit8"); 893179407Sobrien symndx_to_section[RELOC_SECTION_LIT4] = 894179407Sobrien bfd_get_section_by_name (input_bfd, ".lit4"); 895179407Sobrien symndx_to_section[RELOC_SECTION_XDATA] = NULL; 896179407Sobrien symndx_to_section[RELOC_SECTION_PDATA] = NULL; 897179407Sobrien symndx_to_section[RELOC_SECTION_FINI] = 898179407Sobrien bfd_get_section_by_name (input_bfd, ".fini"); 899179407Sobrien symndx_to_section[RELOC_SECTION_LITA] = NULL; 900179407Sobrien symndx_to_section[RELOC_SECTION_ABS] = NULL; 901179407Sobrien 902179407Sobrien ecoff_data (input_bfd)->symndx_to_section = symndx_to_section; 903179407Sobrien } 904179407Sobrien 905179407Sobrien sym_hashes = ecoff_data (input_bfd)->sym_hashes; 906179407Sobrien 907179407Sobrien gp = _bfd_get_gp_value (output_bfd); 908179407Sobrien if (gp == 0) 909179407Sobrien gp_undefined = TRUE; 910179407Sobrien else 911179407Sobrien gp_undefined = FALSE; 912179407Sobrien 913179407Sobrien got_lo = FALSE; 914179407Sobrien 915179407Sobrien ext_rel = (struct external_reloc *) external_relocs; 916179407Sobrien ext_rel_end = ext_rel + input_section->reloc_count; 917179407Sobrien for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++) 918179407Sobrien { 919179407Sobrien struct internal_reloc int_rel; 920179407Sobrien bfd_boolean use_lo = FALSE; 921179407Sobrien bfd_vma addend; 922179407Sobrien reloc_howto_type *howto; 923179407Sobrien struct ecoff_link_hash_entry *h = NULL; 924179407Sobrien asection *s = NULL; 925179407Sobrien bfd_vma relocation; 926179407Sobrien bfd_reloc_status_type r; 927179407Sobrien 928179407Sobrien if (! got_lo) 929179407Sobrien mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel); 930179407Sobrien else 931179407Sobrien { 932179407Sobrien int_rel = lo_int_rel; 933179407Sobrien got_lo = FALSE; 934179407Sobrien } 935179407Sobrien 936179407Sobrien BFD_ASSERT (int_rel.r_type 937179407Sobrien < sizeof mips_howto_table / sizeof mips_howto_table[0]); 938179407Sobrien 939218822Sdim /* The REFHI reloc requires special handling. It must be followed 940218822Sdim by a REFLO reloc, and the addend is formed from both relocs. */ 941218822Sdim if (int_rel.r_type == MIPS_R_REFHI) 942179407Sobrien { 943179407Sobrien struct external_reloc *lo_ext_rel; 944179407Sobrien 945179407Sobrien /* As a GNU extension, permit an arbitrary number of REFHI 946218822Sdim relocs before the REFLO reloc. This permits gcc to emit 947218822Sdim the HI and LO relocs itself. */ 948179407Sobrien for (lo_ext_rel = ext_rel + 1; 949179407Sobrien lo_ext_rel < ext_rel_end; 950179407Sobrien lo_ext_rel++) 951179407Sobrien { 952179407Sobrien mips_ecoff_swap_reloc_in (input_bfd, (PTR) lo_ext_rel, 953179407Sobrien &lo_int_rel); 954179407Sobrien if (lo_int_rel.r_type != int_rel.r_type) 955179407Sobrien break; 956179407Sobrien } 957179407Sobrien 958179407Sobrien if (lo_ext_rel < ext_rel_end 959218822Sdim && lo_int_rel.r_type == MIPS_R_REFLO 960179407Sobrien && int_rel.r_extern == lo_int_rel.r_extern 961179407Sobrien && int_rel.r_symndx == lo_int_rel.r_symndx) 962179407Sobrien { 963179407Sobrien use_lo = TRUE; 964179407Sobrien if (lo_ext_rel == ext_rel + 1) 965179407Sobrien got_lo = TRUE; 966179407Sobrien } 967179407Sobrien } 968179407Sobrien 969179407Sobrien howto = &mips_howto_table[int_rel.r_type]; 970179407Sobrien 971179407Sobrien if (int_rel.r_extern) 972179407Sobrien { 973179407Sobrien h = sym_hashes[int_rel.r_symndx]; 974179407Sobrien /* If h is NULL, that means that there is a reloc against an 975179407Sobrien external symbol which we thought was just a debugging 976179407Sobrien symbol. This should not happen. */ 977179407Sobrien if (h == (struct ecoff_link_hash_entry *) NULL) 978179407Sobrien abort (); 979179407Sobrien } 980179407Sobrien else 981179407Sobrien { 982179407Sobrien if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS) 983179407Sobrien s = NULL; 984179407Sobrien else 985179407Sobrien s = symndx_to_section[int_rel.r_symndx]; 986179407Sobrien 987179407Sobrien if (s == (asection *) NULL) 988179407Sobrien abort (); 989179407Sobrien } 990179407Sobrien 991179407Sobrien /* The GPREL reloc uses an addend: the difference in the GP 992179407Sobrien values. */ 993179407Sobrien if (int_rel.r_type != MIPS_R_GPREL 994179407Sobrien && int_rel.r_type != MIPS_R_LITERAL) 995179407Sobrien addend = 0; 996179407Sobrien else 997179407Sobrien { 998179407Sobrien if (gp_undefined) 999179407Sobrien { 1000179407Sobrien if (! ((*info->callbacks->reloc_dangerous) 1001179407Sobrien (info, _("GP relative relocation used when GP not defined"), 1002179407Sobrien input_bfd, input_section, 1003179407Sobrien int_rel.r_vaddr - input_section->vma))) 1004179407Sobrien return FALSE; 1005179407Sobrien /* Only give the error once per link. */ 1006179407Sobrien gp = 4; 1007179407Sobrien _bfd_set_gp_value (output_bfd, gp); 1008179407Sobrien gp_undefined = FALSE; 1009179407Sobrien } 1010179407Sobrien if (! int_rel.r_extern) 1011179407Sobrien { 1012179407Sobrien /* This is a relocation against a section. The current 1013179407Sobrien addend in the instruction is the difference between 1014179407Sobrien INPUT_SECTION->vma and the GP value of INPUT_BFD. We 1015179407Sobrien must change this to be the difference between the 1016179407Sobrien final definition (which will end up in RELOCATION) 1017179407Sobrien and the GP value of OUTPUT_BFD (which is in GP). */ 1018179407Sobrien addend = ecoff_data (input_bfd)->gp - gp; 1019179407Sobrien } 1020179407Sobrien else if (! info->relocatable 1021179407Sobrien || h->root.type == bfd_link_hash_defined 1022179407Sobrien || h->root.type == bfd_link_hash_defweak) 1023179407Sobrien { 1024179407Sobrien /* This is a relocation against a defined symbol. The 1025179407Sobrien current addend in the instruction is simply the 1026179407Sobrien desired offset into the symbol (normally zero). We 1027179407Sobrien are going to change this into a relocation against a 1028179407Sobrien defined symbol, so we want the instruction to hold 1029179407Sobrien the difference between the final definition of the 1030179407Sobrien symbol (which will end up in RELOCATION) and the GP 1031179407Sobrien value of OUTPUT_BFD (which is in GP). */ 1032179407Sobrien addend = - gp; 1033179407Sobrien } 1034179407Sobrien else 1035179407Sobrien { 1036179407Sobrien /* This is a relocation against an undefined or common 1037179407Sobrien symbol. The current addend in the instruction is 1038179407Sobrien simply the desired offset into the symbol (normally 1039179407Sobrien zero). We are generating relocatable output, and we 1040179407Sobrien aren't going to define this symbol, so we just leave 1041179407Sobrien the instruction alone. */ 1042179407Sobrien addend = 0; 1043179407Sobrien } 1044179407Sobrien } 1045179407Sobrien 1046179407Sobrien if (info->relocatable) 1047179407Sobrien { 1048179407Sobrien /* We are generating relocatable output, and must convert 1049179407Sobrien the existing reloc. */ 1050179407Sobrien if (int_rel.r_extern) 1051179407Sobrien { 1052179407Sobrien if ((h->root.type == bfd_link_hash_defined 1053179407Sobrien || h->root.type == bfd_link_hash_defweak) 1054179407Sobrien && ! bfd_is_abs_section (h->root.u.def.section)) 1055179407Sobrien { 1056179407Sobrien const char *name; 1057179407Sobrien 1058179407Sobrien /* This symbol is defined in the output. Convert 1059179407Sobrien the reloc from being against the symbol to being 1060179407Sobrien against the section. */ 1061179407Sobrien 1062179407Sobrien /* Clear the r_extern bit. */ 1063179407Sobrien int_rel.r_extern = 0; 1064179407Sobrien 1065179407Sobrien /* Compute a new r_symndx value. */ 1066179407Sobrien s = h->root.u.def.section; 1067179407Sobrien name = bfd_get_section_name (output_bfd, 1068179407Sobrien s->output_section); 1069179407Sobrien 1070179407Sobrien int_rel.r_symndx = -1; 1071179407Sobrien switch (name[1]) 1072179407Sobrien { 1073179407Sobrien case 'b': 1074179407Sobrien if (strcmp (name, ".bss") == 0) 1075179407Sobrien int_rel.r_symndx = RELOC_SECTION_BSS; 1076179407Sobrien break; 1077179407Sobrien case 'd': 1078179407Sobrien if (strcmp (name, ".data") == 0) 1079179407Sobrien int_rel.r_symndx = RELOC_SECTION_DATA; 1080179407Sobrien break; 1081179407Sobrien case 'f': 1082179407Sobrien if (strcmp (name, ".fini") == 0) 1083179407Sobrien int_rel.r_symndx = RELOC_SECTION_FINI; 1084179407Sobrien break; 1085179407Sobrien case 'i': 1086179407Sobrien if (strcmp (name, ".init") == 0) 1087179407Sobrien int_rel.r_symndx = RELOC_SECTION_INIT; 1088179407Sobrien break; 1089179407Sobrien case 'l': 1090179407Sobrien if (strcmp (name, ".lit8") == 0) 1091179407Sobrien int_rel.r_symndx = RELOC_SECTION_LIT8; 1092179407Sobrien else if (strcmp (name, ".lit4") == 0) 1093179407Sobrien int_rel.r_symndx = RELOC_SECTION_LIT4; 1094179407Sobrien break; 1095179407Sobrien case 'r': 1096179407Sobrien if (strcmp (name, ".rdata") == 0) 1097179407Sobrien int_rel.r_symndx = RELOC_SECTION_RDATA; 1098179407Sobrien break; 1099179407Sobrien case 's': 1100179407Sobrien if (strcmp (name, ".sdata") == 0) 1101179407Sobrien int_rel.r_symndx = RELOC_SECTION_SDATA; 1102179407Sobrien else if (strcmp (name, ".sbss") == 0) 1103179407Sobrien int_rel.r_symndx = RELOC_SECTION_SBSS; 1104179407Sobrien break; 1105179407Sobrien case 't': 1106179407Sobrien if (strcmp (name, ".text") == 0) 1107179407Sobrien int_rel.r_symndx = RELOC_SECTION_TEXT; 1108179407Sobrien break; 1109179407Sobrien } 1110179407Sobrien 1111179407Sobrien if (int_rel.r_symndx == -1) 1112179407Sobrien abort (); 1113179407Sobrien 1114179407Sobrien /* Add the section VMA and the symbol value. */ 1115179407Sobrien relocation = (h->root.u.def.value 1116179407Sobrien + s->output_section->vma 1117179407Sobrien + s->output_offset); 1118179407Sobrien 1119179407Sobrien /* For a PC relative relocation, the object file 1120179407Sobrien currently holds just the addend. We must adjust 1121179407Sobrien by the address to get the right value. */ 1122179407Sobrien if (howto->pc_relative) 1123218822Sdim relocation -= int_rel.r_vaddr - input_section->vma; 1124179407Sobrien 1125179407Sobrien h = NULL; 1126179407Sobrien } 1127179407Sobrien else 1128179407Sobrien { 1129179407Sobrien /* Change the symndx value to the right one for the 1130179407Sobrien output BFD. */ 1131179407Sobrien int_rel.r_symndx = h->indx; 1132179407Sobrien if (int_rel.r_symndx == -1) 1133179407Sobrien { 1134179407Sobrien /* This symbol is not being written out. */ 1135179407Sobrien if (! ((*info->callbacks->unattached_reloc) 1136179407Sobrien (info, h->root.root.string, input_bfd, 1137179407Sobrien input_section, 1138179407Sobrien int_rel.r_vaddr - input_section->vma))) 1139179407Sobrien return FALSE; 1140179407Sobrien int_rel.r_symndx = 0; 1141179407Sobrien } 1142179407Sobrien relocation = 0; 1143179407Sobrien } 1144179407Sobrien } 1145179407Sobrien else 1146179407Sobrien { 1147179407Sobrien /* This is a relocation against a section. Adjust the 1148179407Sobrien value by the amount the section moved. */ 1149179407Sobrien relocation = (s->output_section->vma 1150179407Sobrien + s->output_offset 1151179407Sobrien - s->vma); 1152179407Sobrien } 1153179407Sobrien 1154179407Sobrien relocation += addend; 1155179407Sobrien addend = 0; 1156179407Sobrien 1157179407Sobrien /* Adjust a PC relative relocation by removing the reference 1158179407Sobrien to the original address in the section and including the 1159218822Sdim reference to the new address. */ 1160218822Sdim if (howto->pc_relative) 1161179407Sobrien relocation -= (input_section->output_section->vma 1162179407Sobrien + input_section->output_offset 1163179407Sobrien - input_section->vma); 1164179407Sobrien 1165179407Sobrien /* Adjust the contents. */ 1166179407Sobrien if (relocation == 0) 1167179407Sobrien r = bfd_reloc_ok; 1168179407Sobrien else 1169179407Sobrien { 1170218822Sdim if (int_rel.r_type != MIPS_R_REFHI) 1171179407Sobrien r = _bfd_relocate_contents (howto, input_bfd, relocation, 1172179407Sobrien (contents 1173179407Sobrien + int_rel.r_vaddr 1174179407Sobrien - input_section->vma)); 1175179407Sobrien else 1176179407Sobrien { 1177179407Sobrien mips_relocate_hi (&int_rel, 1178179407Sobrien use_lo ? &lo_int_rel : NULL, 1179179407Sobrien input_bfd, input_section, contents, 1180218822Sdim relocation); 1181179407Sobrien r = bfd_reloc_ok; 1182179407Sobrien } 1183179407Sobrien } 1184179407Sobrien 1185179407Sobrien /* Adjust the reloc address. */ 1186179407Sobrien int_rel.r_vaddr += (input_section->output_section->vma 1187179407Sobrien + input_section->output_offset 1188179407Sobrien - input_section->vma); 1189179407Sobrien 1190179407Sobrien /* Save the changed reloc information. */ 1191179407Sobrien mips_ecoff_swap_reloc_out (input_bfd, &int_rel, (PTR) ext_rel); 1192179407Sobrien } 1193179407Sobrien else 1194179407Sobrien { 1195179407Sobrien /* We are producing a final executable. */ 1196179407Sobrien if (int_rel.r_extern) 1197179407Sobrien { 1198179407Sobrien /* This is a reloc against a symbol. */ 1199179407Sobrien if (h->root.type == bfd_link_hash_defined 1200179407Sobrien || h->root.type == bfd_link_hash_defweak) 1201179407Sobrien { 1202179407Sobrien asection *hsec; 1203179407Sobrien 1204179407Sobrien hsec = h->root.u.def.section; 1205179407Sobrien relocation = (h->root.u.def.value 1206179407Sobrien + hsec->output_section->vma 1207179407Sobrien + hsec->output_offset); 1208179407Sobrien } 1209179407Sobrien else 1210179407Sobrien { 1211179407Sobrien if (! ((*info->callbacks->undefined_symbol) 1212179407Sobrien (info, h->root.root.string, input_bfd, 1213179407Sobrien input_section, 1214179407Sobrien int_rel.r_vaddr - input_section->vma, TRUE))) 1215179407Sobrien return FALSE; 1216179407Sobrien relocation = 0; 1217179407Sobrien } 1218179407Sobrien } 1219179407Sobrien else 1220179407Sobrien { 1221179407Sobrien /* This is a reloc against a section. */ 1222179407Sobrien relocation = (s->output_section->vma 1223179407Sobrien + s->output_offset 1224179407Sobrien - s->vma); 1225179407Sobrien 1226179407Sobrien /* A PC relative reloc is already correct in the object 1227179407Sobrien file. Make it look like a pcrel_offset relocation by 1228179407Sobrien adding in the start address. */ 1229179407Sobrien if (howto->pc_relative) 1230218822Sdim relocation += int_rel.r_vaddr; 1231179407Sobrien } 1232179407Sobrien 1233218822Sdim if (int_rel.r_type != MIPS_R_REFHI) 1234179407Sobrien r = _bfd_final_link_relocate (howto, 1235179407Sobrien input_bfd, 1236179407Sobrien input_section, 1237179407Sobrien contents, 1238179407Sobrien (int_rel.r_vaddr 1239218822Sdim - input_section->vma), 1240179407Sobrien relocation, 1241179407Sobrien addend); 1242179407Sobrien else 1243179407Sobrien { 1244179407Sobrien mips_relocate_hi (&int_rel, 1245179407Sobrien use_lo ? &lo_int_rel : NULL, 1246218822Sdim input_bfd, input_section, contents, 1247218822Sdim relocation); 1248179407Sobrien r = bfd_reloc_ok; 1249179407Sobrien } 1250179407Sobrien } 1251179407Sobrien 1252179407Sobrien /* MIPS_R_JMPADDR requires peculiar overflow detection. The 1253179407Sobrien instruction provides a 28 bit address (the two lower bits are 1254179407Sobrien implicit zeroes) which is combined with the upper four bits 1255179407Sobrien of the instruction address. */ 1256179407Sobrien if (r == bfd_reloc_ok 1257179407Sobrien && int_rel.r_type == MIPS_R_JMPADDR 1258179407Sobrien && (((relocation 1259179407Sobrien + addend 1260179407Sobrien + (int_rel.r_extern ? 0 : s->vma)) 1261179407Sobrien & 0xf0000000) 1262179407Sobrien != ((input_section->output_section->vma 1263179407Sobrien + input_section->output_offset 1264218822Sdim + (int_rel.r_vaddr - input_section->vma)) 1265179407Sobrien & 0xf0000000))) 1266179407Sobrien r = bfd_reloc_overflow; 1267179407Sobrien 1268179407Sobrien if (r != bfd_reloc_ok) 1269179407Sobrien { 1270179407Sobrien switch (r) 1271179407Sobrien { 1272179407Sobrien default: 1273179407Sobrien case bfd_reloc_outofrange: 1274179407Sobrien abort (); 1275179407Sobrien case bfd_reloc_overflow: 1276179407Sobrien { 1277179407Sobrien const char *name; 1278179407Sobrien 1279179407Sobrien if (int_rel.r_extern) 1280218822Sdim name = NULL; 1281179407Sobrien else 1282179407Sobrien name = bfd_section_name (input_bfd, s); 1283179407Sobrien if (! ((*info->callbacks->reloc_overflow) 1284218822Sdim (info, (h ? &h->root : NULL), name, howto->name, 1285218822Sdim (bfd_vma) 0, input_bfd, input_section, 1286179407Sobrien int_rel.r_vaddr - input_section->vma))) 1287179407Sobrien return FALSE; 1288179407Sobrien } 1289179407Sobrien break; 1290179407Sobrien } 1291179407Sobrien } 1292179407Sobrien } 1293179407Sobrien 1294179407Sobrien return TRUE; 1295179407Sobrien} 1296179407Sobrien 1297179407Sobrien/* This is the ECOFF backend structure. The backend field of the 1298179407Sobrien target vector points to this. */ 1299179407Sobrien 1300179407Sobrienstatic const struct ecoff_backend_data mips_ecoff_backend_data = 1301179407Sobrien{ 1302179407Sobrien /* COFF backend structure. */ 1303179407Sobrien { 1304179407Sobrien (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */ 1305179407Sobrien (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */ 1306179407Sobrien (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */ 1307179407Sobrien (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/ 1308179407Sobrien (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */ 1309179407Sobrien (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */ 1310179407Sobrien (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */ 1311179407Sobrien mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out, 1312179407Sobrien mips_ecoff_swap_scnhdr_out, 1313179407Sobrien FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE, FALSE, 4, FALSE, 2, 1314179407Sobrien mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in, 1315179407Sobrien mips_ecoff_swap_scnhdr_in, NULL, 1316179407Sobrien mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook, 1317179407Sobrien _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags, 1318179407Sobrien _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table, 1319179407Sobrien NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 1320179407Sobrien NULL, NULL 1321179407Sobrien }, 1322179407Sobrien /* Supported architecture. */ 1323179407Sobrien bfd_arch_mips, 1324179407Sobrien /* Initial portion of armap string. */ 1325179407Sobrien "__________", 1326179407Sobrien /* The page boundary used to align sections in a demand-paged 1327179407Sobrien executable file. E.g., 0x1000. */ 1328179407Sobrien 0x1000, 1329179407Sobrien /* TRUE if the .rdata section is part of the text segment, as on the 1330179407Sobrien Alpha. FALSE if .rdata is part of the data segment, as on the 1331179407Sobrien MIPS. */ 1332179407Sobrien FALSE, 1333179407Sobrien /* Bitsize of constructor entries. */ 1334179407Sobrien 32, 1335179407Sobrien /* Reloc to use for constructor entries. */ 1336179407Sobrien &mips_howto_table[MIPS_R_REFWORD], 1337179407Sobrien { 1338179407Sobrien /* Symbol table magic number. */ 1339179407Sobrien magicSym, 1340179407Sobrien /* Alignment of debugging information. E.g., 4. */ 1341179407Sobrien 4, 1342179407Sobrien /* Sizes of external symbolic information. */ 1343179407Sobrien sizeof (struct hdr_ext), 1344179407Sobrien sizeof (struct dnr_ext), 1345179407Sobrien sizeof (struct pdr_ext), 1346179407Sobrien sizeof (struct sym_ext), 1347179407Sobrien sizeof (struct opt_ext), 1348179407Sobrien sizeof (struct fdr_ext), 1349179407Sobrien sizeof (struct rfd_ext), 1350179407Sobrien sizeof (struct ext_ext), 1351179407Sobrien /* Functions to swap in external symbolic data. */ 1352179407Sobrien ecoff_swap_hdr_in, 1353179407Sobrien ecoff_swap_dnr_in, 1354179407Sobrien ecoff_swap_pdr_in, 1355179407Sobrien ecoff_swap_sym_in, 1356179407Sobrien ecoff_swap_opt_in, 1357179407Sobrien ecoff_swap_fdr_in, 1358179407Sobrien ecoff_swap_rfd_in, 1359179407Sobrien ecoff_swap_ext_in, 1360179407Sobrien _bfd_ecoff_swap_tir_in, 1361179407Sobrien _bfd_ecoff_swap_rndx_in, 1362179407Sobrien /* Functions to swap out external symbolic data. */ 1363179407Sobrien ecoff_swap_hdr_out, 1364179407Sobrien ecoff_swap_dnr_out, 1365179407Sobrien ecoff_swap_pdr_out, 1366179407Sobrien ecoff_swap_sym_out, 1367179407Sobrien ecoff_swap_opt_out, 1368179407Sobrien ecoff_swap_fdr_out, 1369179407Sobrien ecoff_swap_rfd_out, 1370179407Sobrien ecoff_swap_ext_out, 1371179407Sobrien _bfd_ecoff_swap_tir_out, 1372179407Sobrien _bfd_ecoff_swap_rndx_out, 1373179407Sobrien /* Function to read in symbolic data. */ 1374179407Sobrien _bfd_ecoff_slurp_symbolic_info 1375179407Sobrien }, 1376179407Sobrien /* External reloc size. */ 1377179407Sobrien RELSZ, 1378179407Sobrien /* Reloc swapping functions. */ 1379179407Sobrien mips_ecoff_swap_reloc_in, 1380179407Sobrien mips_ecoff_swap_reloc_out, 1381179407Sobrien /* Backend reloc tweaking. */ 1382179407Sobrien mips_adjust_reloc_in, 1383179407Sobrien mips_adjust_reloc_out, 1384179407Sobrien /* Relocate section contents while linking. */ 1385179407Sobrien mips_relocate_section, 1386179407Sobrien /* Do final adjustments to filehdr and aouthdr. */ 1387179407Sobrien NULL, 1388179407Sobrien /* Read an element from an archive at a given file position. */ 1389179407Sobrien _bfd_get_elt_at_filepos 1390179407Sobrien}; 1391179407Sobrien 1392179407Sobrien/* Looking up a reloc type is MIPS specific. */ 1393179407Sobrien#define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup 1394218822Sdim#define _bfd_ecoff_bfd_reloc_name_lookup mips_bfd_reloc_name_lookup 1395179407Sobrien 1396179407Sobrien/* Getting relocated section contents is generic. */ 1397179407Sobrien#define _bfd_ecoff_bfd_get_relocated_section_contents \ 1398179407Sobrien bfd_generic_get_relocated_section_contents 1399179407Sobrien 1400179407Sobrien/* Handling file windows is generic. */ 1401179407Sobrien#define _bfd_ecoff_get_section_contents_in_window \ 1402179407Sobrien _bfd_generic_get_section_contents_in_window 1403179407Sobrien 1404179407Sobrien/* Relaxing sections is MIPS specific. */ 1405218822Sdim#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section 1406179407Sobrien 1407179407Sobrien/* GC of sections is not done. */ 1408179407Sobrien#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections 1409179407Sobrien 1410179407Sobrien/* Merging of sections is not done. */ 1411179407Sobrien#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections 1412179407Sobrien 1413218822Sdim#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section 1414179407Sobrien#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group 1415218822Sdim#define _bfd_ecoff_section_already_linked \ 1416218822Sdim _bfd_generic_section_already_linked 1417179407Sobrien 1418179407Sobrienextern const bfd_target ecoff_big_vec; 1419179407Sobrien 1420179407Sobrienconst bfd_target ecoff_little_vec = 1421179407Sobrien{ 1422179407Sobrien "ecoff-littlemips", /* name */ 1423179407Sobrien bfd_target_ecoff_flavour, 1424179407Sobrien BFD_ENDIAN_LITTLE, /* data byte order is little */ 1425179407Sobrien BFD_ENDIAN_LITTLE, /* header byte order is little */ 1426179407Sobrien 1427179407Sobrien (HAS_RELOC | EXEC_P | /* object flags */ 1428179407Sobrien HAS_LINENO | HAS_DEBUG | 1429179407Sobrien HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 1430179407Sobrien 1431179407Sobrien (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 1432179407Sobrien 0, /* leading underscore */ 1433179407Sobrien ' ', /* ar_pad_char */ 1434179407Sobrien 15, /* ar_max_namelen */ 1435179407Sobrien bfd_getl64, bfd_getl_signed_64, bfd_putl64, 1436179407Sobrien bfd_getl32, bfd_getl_signed_32, bfd_putl32, 1437179407Sobrien bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 1438179407Sobrien bfd_getl64, bfd_getl_signed_64, bfd_putl64, 1439179407Sobrien bfd_getl32, bfd_getl_signed_32, bfd_putl32, 1440179407Sobrien bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */ 1441179407Sobrien 1442179407Sobrien {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ 1443179407Sobrien _bfd_ecoff_archive_p, _bfd_dummy_target}, 1444179407Sobrien {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ 1445179407Sobrien _bfd_generic_mkarchive, bfd_false}, 1446179407Sobrien {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ 1447179407Sobrien _bfd_write_archive_contents, bfd_false}, 1448179407Sobrien 1449179407Sobrien BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), 1450179407Sobrien BFD_JUMP_TABLE_COPY (_bfd_ecoff), 1451179407Sobrien BFD_JUMP_TABLE_CORE (_bfd_nocore), 1452179407Sobrien BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), 1453179407Sobrien BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), 1454179407Sobrien BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), 1455179407Sobrien BFD_JUMP_TABLE_WRITE (_bfd_ecoff), 1456179407Sobrien BFD_JUMP_TABLE_LINK (_bfd_ecoff), 1457179407Sobrien BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 1458179407Sobrien 1459179407Sobrien & ecoff_big_vec, 1460179407Sobrien 1461179407Sobrien (PTR) &mips_ecoff_backend_data 1462179407Sobrien}; 1463179407Sobrien 1464179407Sobrienconst bfd_target ecoff_big_vec = 1465179407Sobrien{ 1466179407Sobrien "ecoff-bigmips", /* name */ 1467179407Sobrien bfd_target_ecoff_flavour, 1468179407Sobrien BFD_ENDIAN_BIG, /* data byte order is big */ 1469179407Sobrien BFD_ENDIAN_BIG, /* header byte order is big */ 1470179407Sobrien 1471179407Sobrien (HAS_RELOC | EXEC_P | /* object flags */ 1472179407Sobrien HAS_LINENO | HAS_DEBUG | 1473179407Sobrien HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 1474179407Sobrien 1475179407Sobrien (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 1476179407Sobrien 0, /* leading underscore */ 1477179407Sobrien ' ', /* ar_pad_char */ 1478179407Sobrien 15, /* ar_max_namelen */ 1479179407Sobrien bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1480179407Sobrien bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1481179407Sobrien bfd_getb16, bfd_getb_signed_16, bfd_putb16, 1482179407Sobrien bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1483179407Sobrien bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1484179407Sobrien bfd_getb16, bfd_getb_signed_16, bfd_putb16, 1485179407Sobrien {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ 1486179407Sobrien _bfd_ecoff_archive_p, _bfd_dummy_target}, 1487179407Sobrien {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ 1488179407Sobrien _bfd_generic_mkarchive, bfd_false}, 1489179407Sobrien {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ 1490179407Sobrien _bfd_write_archive_contents, bfd_false}, 1491179407Sobrien 1492179407Sobrien BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), 1493179407Sobrien BFD_JUMP_TABLE_COPY (_bfd_ecoff), 1494179407Sobrien BFD_JUMP_TABLE_CORE (_bfd_nocore), 1495179407Sobrien BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), 1496179407Sobrien BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), 1497179407Sobrien BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), 1498179407Sobrien BFD_JUMP_TABLE_WRITE (_bfd_ecoff), 1499179407Sobrien BFD_JUMP_TABLE_LINK (_bfd_ecoff), 1500179407Sobrien BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 1501179407Sobrien 1502179407Sobrien & ecoff_little_vec, 1503179407Sobrien 1504179407Sobrien (PTR) &mips_ecoff_backend_data 1505179407Sobrien}; 1506179407Sobrien 1507179407Sobrienconst bfd_target ecoff_biglittle_vec = 1508179407Sobrien{ 1509179407Sobrien "ecoff-biglittlemips", /* name */ 1510179407Sobrien bfd_target_ecoff_flavour, 1511179407Sobrien BFD_ENDIAN_LITTLE, /* data byte order is little */ 1512179407Sobrien BFD_ENDIAN_BIG, /* header byte order is big */ 1513179407Sobrien 1514179407Sobrien (HAS_RELOC | EXEC_P | /* object flags */ 1515179407Sobrien HAS_LINENO | HAS_DEBUG | 1516179407Sobrien HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), 1517179407Sobrien 1518179407Sobrien (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA), 1519179407Sobrien 0, /* leading underscore */ 1520179407Sobrien ' ', /* ar_pad_char */ 1521179407Sobrien 15, /* ar_max_namelen */ 1522179407Sobrien bfd_getl64, bfd_getl_signed_64, bfd_putl64, 1523179407Sobrien bfd_getl32, bfd_getl_signed_32, bfd_putl32, 1524179407Sobrien bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */ 1525179407Sobrien bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1526179407Sobrien bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1527179407Sobrien bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ 1528179407Sobrien 1529179407Sobrien {_bfd_dummy_target, coff_object_p, /* bfd_check_format */ 1530179407Sobrien _bfd_ecoff_archive_p, _bfd_dummy_target}, 1531179407Sobrien {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */ 1532179407Sobrien _bfd_generic_mkarchive, bfd_false}, 1533179407Sobrien {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */ 1534179407Sobrien _bfd_write_archive_contents, bfd_false}, 1535179407Sobrien 1536179407Sobrien BFD_JUMP_TABLE_GENERIC (_bfd_ecoff), 1537179407Sobrien BFD_JUMP_TABLE_COPY (_bfd_ecoff), 1538179407Sobrien BFD_JUMP_TABLE_CORE (_bfd_nocore), 1539179407Sobrien BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff), 1540179407Sobrien BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff), 1541179407Sobrien BFD_JUMP_TABLE_RELOCS (_bfd_ecoff), 1542179407Sobrien BFD_JUMP_TABLE_WRITE (_bfd_ecoff), 1543179407Sobrien BFD_JUMP_TABLE_LINK (_bfd_ecoff), 1544179407Sobrien BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 1545179407Sobrien 1546179407Sobrien NULL, 1547179407Sobrien 1548179407Sobrien (PTR) &mips_ecoff_backend_data 1549179407Sobrien}; 1550