-/* MIPS Extended-Coff handler for Binary File Diddling.
- Written by Per Bothner.
+/* BFD back-end for MIPS Extended-Coff files.
+ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009
+ Free Software Foundation, Inc.
+ Original version by Per Bothner.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
- FIXME, Needs Copyleft here. */
-
-/* This does not compile on anything but a MIPS yet (and I haven't been
- able to test it there either since the latest merge!). So it stays
- out by default. */
-#ifdef ECOFF_BFD
-
-#define MIPS 1
-#include "libbfd.h"
#include "sysdep.h"
-#include "libcoff.h" /* to allow easier abstraction-breaking */
-
-#include "intel-coff.h"
-
-
-
+#include "bfd.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "coff/internal.h"
+#include "coff/sym.h"
+#include "coff/symconst.h"
+#include "coff/ecoff.h"
+#include "coff/mips.h"
+#include "libcoff.h"
+#include "libecoff.h"
+\f
+/* Prototypes for static functions. */
+
+static bfd_boolean mips_ecoff_bad_format_hook
+ PARAMS ((bfd *abfd, PTR filehdr));
+static void mips_ecoff_swap_reloc_in
+ PARAMS ((bfd *, PTR, struct internal_reloc *));
+static void mips_ecoff_swap_reloc_out
+ PARAMS ((bfd *, const struct internal_reloc *, PTR));
+static void mips_adjust_reloc_in
+ PARAMS ((bfd *, const struct internal_reloc *, arelent *));
+static void mips_adjust_reloc_out
+ PARAMS ((bfd *, const arelent *, struct internal_reloc *));
+static bfd_reloc_status_type mips_generic_reloc
+ PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
+ asection *section, bfd *output_bfd, char **error));
+static bfd_reloc_status_type mips_refhi_reloc
+ PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
+ asection *section, bfd *output_bfd, char **error));
+static bfd_reloc_status_type mips_reflo_reloc
+ PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
+ asection *section, bfd *output_bfd, char **error));
+static bfd_reloc_status_type mips_gprel_reloc
+ PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, PTR data,
+ asection *section, bfd *output_bfd, char **error));
+static void mips_relocate_hi
+ PARAMS ((struct internal_reloc *refhi, struct internal_reloc *reflo,
+ bfd *input_bfd, asection *input_section, bfd_byte *contents,
+ bfd_vma relocation));
+static bfd_boolean mips_relocate_section
+ PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PTR));
+static reloc_howto_type *mips_bfd_reloc_type_lookup
+ PARAMS ((bfd *, bfd_reloc_code_real_type));
+\f
+/* ECOFF has COFF sections, but the debugging information is stored in
+ a completely different format. ECOFF targets use some of the
+ swapping routines from coffswap.h, and some of the generic COFF
+ routines in coffgen.c, but, unlike the real COFF targets, do not
+ use coffcode.h itself.
+
+ Get the generic COFF swapping routines, except for the reloc,
+ symbol, and lineno ones. Give them ECOFF names. */
+#define MIPSECOFF
+#define NO_COFF_RELOCS
+#define NO_COFF_SYMBOLS
+#define NO_COFF_LINENOS
+#define coff_swap_filehdr_in mips_ecoff_swap_filehdr_in
+#define coff_swap_filehdr_out mips_ecoff_swap_filehdr_out
+#define coff_swap_aouthdr_in mips_ecoff_swap_aouthdr_in
+#define coff_swap_aouthdr_out mips_ecoff_swap_aouthdr_out
+#define coff_swap_scnhdr_in mips_ecoff_swap_scnhdr_in
+#define coff_swap_scnhdr_out mips_ecoff_swap_scnhdr_out
+
+#include "coffswap.h"
+
+/* Get the ECOFF swapping routines. */
+#define ECOFF_32
+#include "ecoffswap.h"
+\f
+/* How to process the various relocs types. */
-static reloc_howto_type howto_table[] =
+static reloc_howto_type mips_howto_table[] =
{
- {0},
- {1},
- {2},
- {3},
- {4},
- {5},
- {6},
- {7},
- {8},
- {9},
- {10},
- {11},
- {12},
- {13},
- {14},
- {15},
- {16},
- { R_RELLONG, 0, 2, 32, 0, 0, true, true},
- {18},
- {19},
- {20},
- {21},
- {22},
- {23},
- {24},
- { R_IPRMED, 2, 2,22,1,0, true, true},
- {26},
-/* What do we do with this - ? */
-#if 1
- { R_OPTCALL, 0,2,32,0,0, true, true},
-#else
- { R_OPTCALL, 0,3,32,0,0, true, true},
-#endif
+ /* Reloc type 0 is ignored. The reloc reading code ensures that
+ this is a reference to the .abs section, which will cause
+ bfd_perform_relocation to do nothing. */
+ HOWTO (MIPS_R_IGNORE, /* type */
+ 0, /* rightshift */
+ 0, /* size (0 = byte, 1 = short, 2 = long) */
+ 8, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ 0, /* special_function */
+ "IGNORE", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* A 16 bit reference to a symbol, normally from a data section. */
+ HOWTO (MIPS_R_REFHALF, /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ mips_generic_reloc, /* special_function */
+ "REFHALF", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* A 32 bit reference to a symbol, normally from a data section. */
+ HOWTO (MIPS_R_REFWORD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ mips_generic_reloc, /* special_function */
+ "REFWORD", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* A 26 bit absolute jump address. */
+ HOWTO (MIPS_R_JMPADDR, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 26, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ /* This needs complex overflow
+ detection, because the upper four
+ bits must match the PC. */
+ mips_generic_reloc, /* special_function */
+ "JMPADDR", /* name */
+ TRUE, /* partial_inplace */
+ 0x3ffffff, /* src_mask */
+ 0x3ffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* The high 16 bits of a symbol value. Handled by the function
+ mips_refhi_reloc. */
+ HOWTO (MIPS_R_REFHI, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ mips_refhi_reloc, /* special_function */
+ "REFHI", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* The low 16 bits of a symbol value. */
+ HOWTO (MIPS_R_REFLO, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ mips_reflo_reloc, /* special_function */
+ "REFLO", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* A reference to an offset from the gp register. Handled by the
+ function mips_gprel_reloc. */
+ HOWTO (MIPS_R_GPREL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips_gprel_reloc, /* special_function */
+ "GPREL", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* A reference to a literal using an offset from the gp register.
+ Handled by the function mips_gprel_reloc. */
+ HOWTO (MIPS_R_LITERAL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips_gprel_reloc, /* special_function */
+ "LITERAL", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (8),
+ EMPTY_HOWTO (9),
+ EMPTY_HOWTO (10),
+ EMPTY_HOWTO (11),
+
+ /* FIXME: This relocation is used (internally only) to represent branches
+ when assembling. It should never appear in output files, and
+ be removed. (It used to be used for embedded-PIC support.) */
+ HOWTO (MIPS_R_PCREL16, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips_generic_reloc, /* special_function */
+ "PCREL16", /* name */
+ TRUE, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ TRUE), /* pcrel_offset */
};
+#define MIPS_HOWTO_COUNT \
+ (sizeof mips_howto_table / sizeof mips_howto_table[0])
+\f
+/* See whether the magic number matches. */
-#define ALIGN(this, boundary) \
- ((( (this) + ((boundary) -1)) & (~((boundary)-1))))
-
-
-/* Support for Motorola 88k bcs coff as well as Intel 960 coff */
-
-
-#include <stdio.h>
-#include <string.h>
+static bfd_boolean
+mips_ecoff_bad_format_hook (abfd, filehdr)
+ bfd *abfd;
+ PTR filehdr;
+{
+ struct internal_filehdr *internal_f = (struct internal_filehdr *) filehdr;
+ switch (internal_f->f_magic)
+ {
+ case MIPS_MAGIC_1:
+ /* I don't know what endianness this implies. */
+ return TRUE;
+
+ case MIPS_MAGIC_BIG:
+ case MIPS_MAGIC_BIG2:
+ case MIPS_MAGIC_BIG3:
+ return bfd_big_endian (abfd);
+
+ case MIPS_MAGIC_LITTLE:
+ case MIPS_MAGIC_LITTLE2:
+ case MIPS_MAGIC_LITTLE3:
+ return bfd_little_endian (abfd);
+
+ default:
+ return FALSE;
+ }
+}
+\f
+/* Reloc handling. MIPS ECOFF relocs are packed into 8 bytes in
+ external form. They use a bit which indicates whether the symbol
+ is external. */
-/* Align an address by rounding it up to a power of two. It leaves the
- address unchanged if align == 0 (2^0 = alignment of 1 byte) */
-#define i960_align(addr, align) \
- ( ((addr) + ((1<<(align))-1)) & (-1 << (align)))
+/* Swap a reloc in. */
-#define TAG_SECTION_NAME ".tagbits"
+static void
+mips_ecoff_swap_reloc_in (abfd, ext_ptr, intern)
+ bfd *abfd;
+ PTR ext_ptr;
+ struct internal_reloc *intern;
+{
+ const RELOC *ext = (RELOC *) ext_ptr;
-/* Libraries shouldn't be doing this stuff anyway! */
-void fatal();
-/* void warning(); */
-\f
+ intern->r_vaddr = H_GET_32 (abfd, ext->r_vaddr);
+ if (bfd_header_big_endian (abfd))
+ {
+ intern->r_symndx = (((int) ext->r_bits[0]
+ << RELOC_BITS0_SYMNDX_SH_LEFT_BIG)
+ | ((int) ext->r_bits[1]
+ << RELOC_BITS1_SYMNDX_SH_LEFT_BIG)
+ | ((int) ext->r_bits[2]
+ << RELOC_BITS2_SYMNDX_SH_LEFT_BIG));
+ intern->r_type = ((ext->r_bits[3] & RELOC_BITS3_TYPE_BIG)
+ >> RELOC_BITS3_TYPE_SH_BIG);
+ intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0;
+ }
+ else
+ {
+ intern->r_symndx = (((int) ext->r_bits[0]
+ << RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE)
+ | ((int) ext->r_bits[1]
+ << RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE)
+ | ((int) ext->r_bits[2]
+ << RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE));
+ intern->r_type = (((ext->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
+ >> RELOC_BITS3_TYPE_SH_LITTLE)
+ | ((ext->r_bits[3] & RELOC_BITS3_TYPEHI_LITTLE)
+ << RELOC_BITS3_TYPEHI_SH_LITTLE));
+ intern->r_extern = (ext->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0;
+ }
+}
-/* initialize a section structure with information
- * peculiar to this particular implementation of coff
- */
+/* Swap a reloc out. */
static void
-ecoff_new_section_hook(abfd, section)
-bfd *abfd;
-asection *section;
+mips_ecoff_swap_reloc_out (abfd, intern, dst)
+ bfd *abfd;
+ const struct internal_reloc *intern;
+ PTR dst;
{
+ RELOC *ext = (RELOC *) dst;
+ long r_symndx;
+
+ BFD_ASSERT (intern->r_extern
+ || (intern->r_symndx >= 0 && intern->r_symndx <= 12));
+
+ r_symndx = intern->r_symndx;
- section->output_file_alignment = DEFAULT_SECTION_ALIGNMENT;
- section->subsection_alignment = section->output_file_alignment;
- if (abfd->flags & D_PAGED)
+ H_PUT_32 (abfd, intern->r_vaddr, ext->r_vaddr);
+ if (bfd_header_big_endian (abfd))
{
- /**
- If the output object file is demand paged then the
- text section starts at the filehdr, with the first
- usefull bit of data at the end of the filehdr+opthdr+
- scnhdrs. Since we don't know how many sections will
- be put into the output file, we have to recalculate
- the section pads after each additional section has
- been created
- **/
- asection *ptr = abfd->sections;
- unsigned int padding = FILHSZ + AOUTSZ +SCNHSZ * abfd->section_count;
-
- padding = ALIGN(padding, ptr->output_file_alignment);
- while (ptr)
- {
- ptr->start_pad = padding;
- /* Only the first section is padded */
- padding = 0;
- ptr = ptr->next;
- }
+ ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_BIG;
+ ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_BIG;
+ ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_BIG;
+ ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_BIG)
+ & RELOC_BITS3_TYPE_BIG)
+ | (intern->r_extern ? RELOC_BITS3_EXTERN_BIG : 0));
}
- else
+ else
{
-
- /* If the object is not demand paged, then all the sections
- have no padding
- */
- section->start_pad = 0;
+ ext->r_bits[0] = r_symndx >> RELOC_BITS0_SYMNDX_SH_LEFT_LITTLE;
+ ext->r_bits[1] = r_symndx >> RELOC_BITS1_SYMNDX_SH_LEFT_LITTLE;
+ ext->r_bits[2] = r_symndx >> RELOC_BITS2_SYMNDX_SH_LEFT_LITTLE;
+ ext->r_bits[3] = (((intern->r_type << RELOC_BITS3_TYPE_SH_LITTLE)
+ & RELOC_BITS3_TYPE_LITTLE)
+ | ((intern->r_type >> RELOC_BITS3_TYPEHI_SH_LITTLE
+ & RELOC_BITS3_TYPEHI_LITTLE))
+ | (intern->r_extern ? RELOC_BITS3_EXTERN_LITTLE : 0));
}
+}
+/* Finish canonicalizing a reloc. Part of this is generic to all
+ ECOFF targets, and that part is in ecoff.c. The rest is done in
+ this backend routine. It must fill in the howto field. */
+static void
+mips_adjust_reloc_in (abfd, intern, rptr)
+ bfd *abfd;
+ const struct internal_reloc *intern;
+ arelent *rptr;
+{
+ if (intern->r_type > MIPS_R_PCREL16)
+ abort ();
+
+ if (! intern->r_extern
+ && (intern->r_type == MIPS_R_GPREL
+ || intern->r_type == MIPS_R_LITERAL))
+ rptr->addend += ecoff_data (abfd)->gp;
+ /* If the type is MIPS_R_IGNORE, make sure this is a reference to
+ the absolute section so that the reloc is ignored. */
+ if (intern->r_type == MIPS_R_IGNORE)
+ rptr->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr;
+
+ rptr->howto = &mips_howto_table[intern->r_type];
}
-/* actually it makes itself and its children from the file headers */
-static boolean
-make_a_section_from_file (abfd, hdr)
-bfd *abfd;
- struct scnhdr *hdr;
+/* Make any adjustments needed to a reloc before writing it out. None
+ are needed for MIPS. */
+
+static void
+mips_adjust_reloc_out (abfd, rel, intern)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ const arelent *rel ATTRIBUTE_UNUSED;
+ struct internal_reloc *intern ATTRIBUTE_UNUSED;
{
- asection *return_section ;
-
- { char *name = (char *)xmalloc(9);
-
- strncpy(name, (char *)&hdr->s_name[0], 8);
-
- return_section = bfd_make_section(abfd, name);
- (return_section->name)[8] = 0;
- }
-
- /* s_paddr is presumed to be = to s_vaddr */
- /* FIXME -- needs to call swapping routines */
-#define assign(to, from) return_section->to = hdr->from
- assign (vma, s_vaddr);
- assign (original_vma, s_vaddr);
- assign (size, s_size);
- assign (filepos, s_scnptr);
- assign (rel_filepos, s_relptr);
- assign (reloc_count, s_nreloc);
-#ifdef I960
- assign (alignment, s_align);
-#endif
- assign (line_filepos, s_lnnoptr);
-/* return_section->linesize = hdr->s_nlnno * sizeof (struct lineno);*/
-
-#undef assign
- return_section->lineno_count = hdr->s_nlnno;
- return_section->userdata = (void *)NULL;
- return_section->next = (asection *)NULL;
- if ((hdr->s_flags & STYP_TEXT) || (hdr->s_flags & STYP_DATA))
- return_section->flags = (SEC_LOAD | SEC_ALLOC);
- else if (hdr->s_flags & STYP_BSS)
- return_section->flags = SEC_ALLOC;
-
- if (hdr->s_nreloc != 0) return_section->flags |= SEC_RELOC;
-
- return true;
}
-bfd_target *
-ecoff_real_object_p (abfd, nscns, opthdr)
- bfd *abfd;
- unsigned short nscns, opthdr;
+/* ECOFF relocs are either against external symbols, or against
+ sections. If we are producing relocatable output, and the reloc
+ is against an external symbol, and nothing has given us any
+ additional addend, the resulting reloc will also be against the
+ same symbol. In such a case, we don't want to change anything
+ about the way the reloc is handled, since it will all be done at
+ final link time. Rather than put special case code into
+ bfd_perform_relocation, all the reloc types use this howto
+ function. It just short circuits the reloc if producing
+ relocatable output against an external symbol. */
+
+static bfd_reloc_status_type
+mips_generic_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data ATTRIBUTE_UNUSED;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
{
- struct icofdata *tdata;
- char *file_info; /* buffer for all the headers */
- long readsize; /* length of file_info */
- struct filehdr* filehdr; /* points into file_info */
- struct scnhdr *sections; /* points into file_info */
-
- /* OK, now we know the format, read in the filehdr, soi-disant
- "optional header", and all the sections.*/
- readsize = sizeof(struct filehdr) + opthdr + (nscns * sizeof (struct scnhdr));
- file_info = xmalloc (readsize);
- if (file_info == NULL) {
- bfd_error = no_memory;
- return 0;
- }
- if (bfd_seek (abfd, 0, false) < 0) return 0;
- if (bfd_read (file_info, 1, readsize, abfd) != readsize) return 0;
- filehdr = (struct filehdr *) file_info;
- sections = (struct scnhdr *) (file_info + sizeof (struct filehdr) + opthdr);
-
- /* Now copy data as required; construct all asections etc */
- tdata = (struct icofdata *) xmalloc (sizeof (struct icofdata) +
- sizeof (AOUTHDR));
- if (tdata == NULL) {
- bfd_error = no_memory;
- return 0;
- }
-
- if (nscns != 0)
- {
- unsigned int i;
- for (i = 0; i < nscns; i++)
- {
- make_a_section_from_file (abfd, sections + i);
- }
- }
-
-#ifdef I960
- /* OK, now make a section for the tagbits if there were any */
-#if 0
- {
- AOUTHDR *aouthdr; /* points into tdata! */
- aouthdr = (AOUTHDR *) (((char *) tdata) + sizeof (struct icofdata));
- if (aouthdr->tagentries != 0) {
- asection *tag_section = (asection *) xmalloc (sizeof (asection));
- if (tag_section == NULL) {
- free (tdata);
- return 0;
- }
- tag_section->size = aouthdr->tagentries * sizeof (TAGBITS);
- tag_section->name = TAG_SECTION_NAME;
- tag_section->filepos = readsize; /* not surprisingly */
- /* Put this one first */
- tag_section->next = abfd->sections;
- abfd->sections = tag_section;
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
}
- }
-#endif
-#endif
-abfd->flags |= HAS_RELOC | HAS_LINENO | HAS_LOCALS;
-
-
- /* FIXME, the guess should be set by OR-ing info from the sections */
- if ((filehdr->f_flags & F_RELFLG) != F_RELFLG) abfd->flags &= ~HAS_RELOC;
- if ((filehdr->f_flags & F_EXEC) == F_EXEC) abfd->flags |= EXEC_P;
- if ((filehdr->f_flags & F_LNNO) != F_LNNO) abfd->flags &= ~HAS_LINENO;
- if ((filehdr->f_flags & F_LSYMS) != F_LSYMS) abfd->flags &= ~HAS_LOCALS;
- abfd->tdata = tdata;
- bfd_get_symcount (abfd) = filehdr->f_nsyms;
- if (filehdr->f_nsyms) abfd->flags |= HAS_SYMS;
-
- tdata->sym_filepos = filehdr->f_symptr;
- tdata->hdr = (struct aouthdr *)(file_info + sizeof (struct filehdr));
- tdata->symbols = (esymbol *)NULL;
- bfd_get_start_address (abfd) = exec_hdr (abfd)->entry;
- return abfd->xvec;
+
+ return bfd_reloc_continue;
}
-bfd_target *
-ecoff_object_p (abfd)
- bfd *abfd;
+/* Do a REFHI relocation. This has to be done in combination with a
+ REFLO reloc, because there is a carry from the REFLO to the REFHI.
+ Here we just save the information we need; we do the actual
+ relocation when we see the REFLO. MIPS ECOFF requires that the
+ REFLO immediately follow the REFHI. As a GNU extension, we permit
+ an arbitrary number of HI relocs to be associated with a single LO
+ reloc. This extension permits gcc to output the HI and LO relocs
+ itself. */
+
+struct mips_hi
{
- unsigned short magic, nscns, opthdr;
+ struct mips_hi *next;
+ bfd_byte *addr;
+ bfd_vma addend;
+};
+
+/* FIXME: This should not be a static variable. */
+
+static struct mips_hi *mips_refhi_list;
+
+static bfd_reloc_status_type
+mips_refhi_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message ATTRIBUTE_UNUSED;
+{
+ bfd_reloc_status_type ret;
+ bfd_vma relocation;
+ struct mips_hi *n;
+
+ /* If we're relocating, and this an external symbol, we don't want
+ to change anything. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ ret = bfd_reloc_ok;
+ if (bfd_is_und_section (symbol->section)
+ && output_bfd == (bfd *) NULL)
+ ret = bfd_reloc_undefined;
+
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
- bfd_error = no_error;
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+ relocation += reloc_entry->addend;
- /* figure out how much to read */
- if (bfd_read (&magic, 1, sizeof (magic), abfd) != sizeof (magic))
- return 0;
+ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ return bfd_reloc_outofrange;
- magic = bfd_h_getshort (abfd, (unsigned char *)&magic);
- if (magic != (abfd->xvec->byteorder_big_p ? 0x160 : 0x162)) {
- bfd_error = wrong_format;
- return 0;
- }
- if (bfd_read (&nscns, 1, sizeof (nscns), abfd) != sizeof (nscns))
- return 0;
- nscns = bfd_h_getshort (abfd, (unsigned char *)&nscns);
+ /* Save the information, and let REFLO do the actual relocation. */
+ n = (struct mips_hi *) bfd_malloc ((bfd_size_type) sizeof *n);
+ if (n == NULL)
+ return bfd_reloc_outofrange;
+ n->addr = (bfd_byte *) data + reloc_entry->address;
+ n->addend = relocation;
+ n->next = mips_refhi_list;
+ mips_refhi_list = n;
- if (bfd_seek (abfd, ((sizeof (long)) * 3), true) < 0) return false;
- if (bfd_read (&opthdr, 1, sizeof (opthdr), abfd) != sizeof (opthdr))
- return 0;
- opthdr = bfd_h_getshort (abfd, (unsigned char *)&opthdr);
+ if (output_bfd != (bfd *) NULL)
+ reloc_entry->address += input_section->output_offset;
- return ecoff_real_object_p (abfd, nscns, opthdr);
+ return ret;
}
-static boolean
-ecoff_mkobject (abfd)
+/* Do a REFLO relocation. This is a straightforward 16 bit inplace
+ relocation; this function exists in order to do the REFHI
+ relocation described above. */
+
+static bfd_reloc_status_type
+mips_reflo_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
{
- char *rawptr;
-
-
- bfd_error = no_error;
+ if (mips_refhi_list != NULL)
+ {
+ struct mips_hi *l;
- /* Use an intermediate variable for clarity */
- rawptr = xmalloc (sizeof (struct icofdata) + sizeof (AOUTHDR));
- if (rawptr == NULL) {
- bfd_error = no_memory;
- return false;
- }
+ l = mips_refhi_list;
+ while (l != NULL)
+ {
+ unsigned long insn;
+ unsigned long val;
+ unsigned long vallo;
+ struct mips_hi *next;
+
+ /* Do the REFHI relocation. Note that we actually don't
+ need to know anything about the REFLO itself, except
+ where to find the low 16 bits of the addend needed by the
+ REFHI. */
+ insn = bfd_get_32 (abfd, l->addr);
+ vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
+ & 0xffff);
+ val = ((insn & 0xffff) << 16) + vallo;
+ val += l->addend;
+
+ /* The low order 16 bits are always treated as a signed
+ value. Therefore, a negative value in the low order bits
+ requires an adjustment in the high order bits. We need
+ to make this adjustment in two ways: once for the bits we
+ took from the data, and once for the bits we are putting
+ back in to the data. */
+ if ((vallo & 0x8000) != 0)
+ val -= 0x10000;
+ if ((val & 0x8000) != 0)
+ val += 0x10000;
+
+ insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
+ bfd_put_32 (abfd, (bfd_vma) insn, l->addr);
+
+ next = l->next;
+ free (l);
+ l = next;
+ }
- abfd->tdata = (struct icofdata *) rawptr;
- exec_hdr (abfd) = (AOUTHDR *) (rawptr + sizeof (struct icofdata));
+ mips_refhi_list = NULL;
+ }
- return true;
+ /* Now do the REFLO reloc in the usual way. */
+ return mips_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
}
-\f
-static void
-ecoff_count_linenumbers(abfd)
-bfd *abfd;
+
+/* Do a GPREL relocation. This is a 16 bit value which must become
+ the offset from the gp register. */
+
+static bfd_reloc_status_type
+mips_gprel_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
{
- unsigned int limit = bfd_get_symcount(abfd);
- unsigned int i = 0;
- esymbol **p = (esymbol **)(abfd->outsymbols);
- {
- asection *s = abfd->sections;
- while (s) {
- if (s->lineno_count != 0) {
- fatal("Bad initial state");
- }
- s = s->next;
+ bfd_boolean relocatable;
+ bfd_vma gp;
+ bfd_vma relocation;
+ unsigned long val;
+ unsigned long insn;
+
+ /* If we're relocating, and this is an external symbol with no
+ addend, we don't want to change anything. We will only have an
+ addend if this is a newly created reloc, not read from an ECOFF
+ file. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (output_bfd != (bfd *) NULL)
+ relocatable = TRUE;
+ else
+ {
+ relocatable = FALSE;
+ output_bfd = symbol->section->output_section->owner;
}
- }
- while (i < limit)
+ if (bfd_is_und_section (symbol->section) && ! relocatable)
+ return bfd_reloc_undefined;
+
+ /* We have to figure out the gp value, so that we can adjust the
+ symbol value correctly. We look up the symbol _gp in the output
+ BFD. If we can't find it, we're stuck. We cache it in the ECOFF
+ target data. We don't need to adjust the symbol value for an
+ external symbol if we are producing relocatable output. */
+ gp = _bfd_get_gp_value (output_bfd);
+ if (gp == 0
+ && (! relocatable
+ || (symbol->flags & BSF_SECTION_SYM) != 0))
{
- esymbol *q = *p;
- if (q->c.lineno)
+ if (relocatable)
{
- /* This symbol has a linenumber, increment the
- * owning section's linenumber count */
- alent *l = q->c.lineno;
- q->c.section->lineno_count++;
- l++;
- while (l->line_number) {
- q->c.section->lineno_count++;
- l++;
- }
+ /* Make up a value. */
+ gp = symbol->section->output_section->vma + 0x4000;
+ _bfd_set_gp_value (output_bfd, gp);
}
- p++;
- i++;
- }
-}
+ else
+ {
+ unsigned int count;
+ asymbol **sym;
+ unsigned int i;
-/*
- run through the internal symbol table and make all the
- pointers and things within the table point to the right places
- */
+ count = bfd_get_symcount (output_bfd);
+ sym = bfd_get_outsymbols (output_bfd);
-static void
-ecoff_mangle_symbols(abfd)
-bfd *abfd;
-{
- esymbol **p = (esymbol **)(abfd->outsymbols);
- unsigned int native_index = 0;
- unsigned int last_file_index = 0;
- unsigned int limit = bfd_get_symcount(abfd);
- struct syment *last_file_symbol = (struct syment *)NULL;
- while (limit--) {
- esymbol *q = *p;
- struct syment *native = q->native;
- if(native) {
- /* Alter the native representation */
-
- native->n_value = q->c.value;
- if (q->c.flags & BSF_FORT_COMM) {
- native->n_scnum = 0;
- }
- else if (q->c.flags & BSF_DEBUGGING) {
- native->n_scnum = -2;
- }
- else if (q->c.flags & BSF_UNDEFINED) {
- native->n_scnum = 0;
- }
- else if (q->c.flags & BSF_ABSOLUTE) {
- native->n_scnum = -1;
- }
- else {
- native->n_scnum = q->c.section->index + 1;
- }
- if (native->n_numaux)
- {
- union auxent *a = (union auxent *)(native+1);
- /* Relocate symbol indexes */
- if (ISFCN(native->n_type))
- {
- a->x_sym.x_fcnary.x_fcn.x_endndx += last_file_index;
- }
- else if(native->n_sclass == C_BLOCK && q->c.name[1] == 'b')
+ if (sym == (asymbol **) NULL)
+ i = count;
+ else
{
- a->x_sym.x_fcnary.x_fcn.x_endndx += last_file_index;
+ for (i = 0; i < count; i++, sym++)
+ {
+ register const char *name;
+
+ name = bfd_asymbol_name (*sym);
+ if (*name == '_' && strcmp (name, "_gp") == 0)
+ {
+ gp = bfd_asymbol_value (*sym);
+ _bfd_set_gp_value (output_bfd, gp);
+ break;
+ }
+ }
}
- else if (native->n_sclass == C_STRTAG)
- {
- a->x_sym.x_fcnary.x_fcn.x_endndx += last_file_index;
- }
- else if (native->n_sclass == C_MOS || native->n_sclass == C_EOS || native->n_sclass == C_MOE)
+ if (i >= count)
{
- a->x_sym.x_tagndx += last_file_index;
+ /* Only get the error once. */
+ gp = 4;
+ _bfd_set_gp_value (output_bfd, gp);
+ *error_message =
+ (char *) _("GP relative relocation when _gp not defined");
+ return bfd_reloc_dangerous;
}
}
-
-
- switch (native->n_sclass) {
- case C_MOS:
- case C_EOS:
- case C_REGPARM:
- case C_REG:
- case 19: /*C_REGARG:FIXME */
- /* Fix so that they have an absolute section */
- native->n_scnum= -1;
- break;
-
- case C_FILE:
- /* Chain all the .file symbols together */
- if(last_file_symbol) {
- last_file_symbol->n_value = native_index;
- }
- last_file_symbol = native;
- last_file_index = native_index;
- break;
- case C_NULL:
- case C_AUTO:
- case C_EXT:
- case C_EXTDEF:
- case C_LABEL:
- case C_ULABEL:
- case C_USTATIC:
- case C_STRTAG:
- case C_FCN:
- case C_BLOCK:
- case C_STAT:
- case C_LEAFPROC:
- break;
- default:
- /* Bogus: This should be returning an error code, not printing
- something out! */
- /* warning("Unrecognised sclass %d", native->n_sclass); */
- break;
- }
- native_index += 1 + native->n_numaux;
}
- else {
- native_index++;
- }
- p++;
- }
-}
-static void
-ecoff_write_symbols(abfd)
-bfd *abfd;
-{
-}
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
-void
-ecoff_write_linenumbers(abfd)
-bfd *abfd;
-{
-}
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+ if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
+ return bfd_reloc_outofrange;
-asymbol *
-ecoff_make_empty_symbol(abfd, n)
-bfd *abfd;
-unsigned int n;
-{
- unsigned int j;
- esymbol *new = (esymbol *)xmalloc(sizeof(esymbol) * n);
- for (j= 0; j < n; j++) {
- new[j].native = 0;
- new[j].c.lineno = (alent *)NULL;
- }
- return (asymbol *)new;
-}
+ insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
-/*SUPPRESS 558*/
-/*SUPPRESS 529*/
-boolean
-ecoff_write_object_contents (abfd)
- bfd *abfd;
-{
- return false;
-}
-\f
-/* Calculate the file position for each section. */
+ /* Set val to the offset into the section or symbol. */
+ val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
+ if (val & 0x8000)
+ val -= 0x10000;
-static void
-ecoff_compute_section_file_positions (abfd)
- bfd *abfd;
-{
- file_ptr sofar = sizeof (struct filehdr) + sizeof (AOUTHDR);
- asection *current;
-
- sofar += abfd->section_count * sizeof (struct scnhdr);
- for (current = abfd->sections; current != NULL; current = current->next) {
- sofar = ALIGN(sofar, current->output_file_alignment);
- current->filepos = sofar;
- /* Only add sections which are loadable */
- if (current->flags & SEC_LOAD) sofar += current->size;
-#if 0
- if(current->filepos & (current->alignment-1)) {
- sofar += current->alignment - (current->filepos &(current->alignment-1));
- current->filepos = (current->filepos + current->alignment) & -current->alignment;
- }
-#endif
- }
- obj_relocbase (abfd) = sofar;
-}
-
-boolean
-ecoff_set_section_contents (abfd, section, location, offset, count)
- bfd *abfd;
- sec_ptr section;
- unsigned char *location;
- file_ptr offset;
- int count;
-{
- return false;
-}
-
-boolean
-ecoff_set_section_linenos (abfd, section, location, offset, count)
- bfd *abfd;
- sec_ptr section;
- unsigned char *location;
- file_ptr offset;
- int count;
-{
- return 0;
-}
-\f
-
-boolean
-ecoff_close_and_cleanup (abfd)
- bfd *abfd;
-{
- return false;
-}
-\f
+ /* Adjust val for the final section location and GP value. If we
+ are producing relocatable output, we don't want to do this for
+ an external symbol. */
+ if (! relocatable
+ || (symbol->flags & BSF_SECTION_SYM) != 0)
+ val += relocation - gp;
+ insn = (insn &~ (unsigned) 0xffff) | (val & 0xffff);
+ bfd_put_32 (abfd, (bfd_vma) insn, (bfd_byte *) data + reloc_entry->address);
+ if (relocatable)
+ reloc_entry->address += input_section->output_offset;
+ /* Make sure it fit in 16 bits. */
+ if ((long) val >= 0x8000 || (long) val < -0x8000)
+ return bfd_reloc_overflow;
-static void *
-buy_and_read(abfd, where, relative, size)
-bfd *abfd;
-int where;
-boolean relative;
-unsigned int size;
-{
- void *area = (void *)xmalloc(size);
- if (!area) {
- bfd_error = no_memory;
- return 0;
- }
- bfd_seek(abfd, where, relative);
- if (bfd_read(area, 1, size, abfd) != size){
- bfd_error = system_call_error;
- free(area);
- return 0;
- }
- return area;
+ return bfd_reloc_ok;
}
-static
-struct sec_struct *section_from_bfd_index(abfd, index)
-bfd *abfd;
-int index;
-{
-if (index > 0) {
- struct sec_struct *answer = abfd->sections;
-
- while (--index) {
- answer = answer->next;
- }
- return answer;
-}
-return 0;
-}
+/* Get the howto structure for a generic reloc type. */
-static int
-ecoff_get_symcount_upper_bound (abfd)
- bfd *abfd;
+static reloc_howto_type *
+mips_bfd_reloc_type_lookup (abfd, code)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ bfd_reloc_code_real_type code;
{
-fatal("call to ecoff_get_symcount_upper_bound");
-return 0;
-}
+ int mips_type;
-static symindex
-ecoff_get_first_symbol (abfd)
- bfd * abfd;
-{
- return 0;
-}
+ switch (code)
+ {
+ case BFD_RELOC_16:
+ mips_type = MIPS_R_REFHALF;
+ break;
+ case BFD_RELOC_32:
+ case BFD_RELOC_CTOR:
+ mips_type = MIPS_R_REFWORD;
+ break;
+ case BFD_RELOC_MIPS_JMP:
+ mips_type = MIPS_R_JMPADDR;
+ break;
+ case BFD_RELOC_HI16_S:
+ mips_type = MIPS_R_REFHI;
+ break;
+ case BFD_RELOC_LO16:
+ mips_type = MIPS_R_REFLO;
+ break;
+ case BFD_RELOC_GPREL16:
+ mips_type = MIPS_R_GPREL;
+ break;
+ case BFD_RELOC_MIPS_LITERAL:
+ mips_type = MIPS_R_LITERAL;
+ break;
+ case BFD_RELOC_16_PCREL_S2:
+ mips_type = MIPS_R_PCREL16;
+ break;
+ default:
+ return (reloc_howto_type *) NULL;
+ }
-static symindex
-ecoff_get_next_symbol (abfd, oidx)
- bfd *abfd;
- symindex oidx;
-{
- if (oidx == BFD_NO_MORE_SYMBOLS) return BFD_NO_MORE_SYMBOLS;
- return ++oidx >= bfd_get_symcount (abfd) ? BFD_NO_MORE_SYMBOLS : oidx;
+ return &mips_howto_table[mips_type];
}
-static char *
-ecoff_symbol_name (abfd, idx)
- bfd *abfd;
- symindex idx;
+static reloc_howto_type *
+mips_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+ const char *r_name)
{
- return (obj_symbols (abfd) + idx)->c.name;
-}
+ unsigned int i;
-static long
-ecoff_symbol_value (abfd, idx)
- bfd *abfd;
- symindex idx;
-{
- return (obj_symbols (abfd) + idx)->c.value;
+ for (i = 0;
+ i < sizeof (mips_howto_table) / sizeof (mips_howto_table[0]);
+ i++)
+ if (mips_howto_table[i].name != NULL
+ && strcasecmp (mips_howto_table[i].name, r_name) == 0)
+ return &mips_howto_table[i];
+
+ return NULL;
}
+\f
+/* A helper routine for mips_relocate_section which handles the REFHI
+ relocations. The REFHI relocation must be followed by a REFLO
+ relocation, and the addend used is formed from the addends of both
+ instructions. */
-static symclass
-ecoff_classify_symbol (abfd, idx)
- bfd *abfd;
- symindex idx;
+static void
+mips_relocate_hi (refhi, reflo, input_bfd, input_section, contents,
+ relocation)
+ struct internal_reloc *refhi;
+ struct internal_reloc *reflo;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ bfd_vma relocation;
{
- esymbol *sym = obj_symbols (abfd) + idx;
-
- if ((sym->c.flags & BSF_FORT_COMM) != 0) return bfd_symclass_fcommon;
- if ((sym->c.flags & BSF_GLOBAL) != 0) return bfd_symclass_global;
- if ((sym->c.flags & BSF_DEBUGGING) != 0) return bfd_symclass_debugger;
- if ((sym->c.flags & BSF_UNDEFINED) != 0) return bfd_symclass_undefined;
-
- return bfd_symclass_unknown;
+ unsigned long insn;
+ unsigned long val;
+ unsigned long vallo;
+
+ if (refhi == NULL)
+ return;
+
+ insn = bfd_get_32 (input_bfd,
+ contents + refhi->r_vaddr - input_section->vma);
+ if (reflo == NULL)
+ vallo = 0;
+ else
+ vallo = (bfd_get_32 (input_bfd,
+ contents + reflo->r_vaddr - input_section->vma)
+ & 0xffff);
+
+ val = ((insn & 0xffff) << 16) + vallo;
+ val += relocation;
+
+ /* The low order 16 bits are always treated as a signed value.
+ Therefore, a negative value in the low order bits requires an
+ adjustment in the high order bits. We need to make this
+ adjustment in two ways: once for the bits we took from the data,
+ and once for the bits we are putting back in to the data. */
+ if ((vallo & 0x8000) != 0)
+ val -= 0x10000;
+
+ if ((val & 0x8000) != 0)
+ val += 0x10000;
+
+ insn = (insn &~ (unsigned) 0xffff) | ((val >> 16) & 0xffff);
+ bfd_put_32 (input_bfd, (bfd_vma) insn,
+ contents + refhi->r_vaddr - input_section->vma);
}
-static boolean
-ecoff_symbol_hasclass (abfd, idx, class)
- bfd *abfd;
- symindex idx;
- symclass class;
+/* Relocate a section while linking a MIPS ECOFF file. */
+
+static bfd_boolean
+mips_relocate_section (output_bfd, info, input_bfd, input_section,
+ contents, external_relocs)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ asection *input_section;
+ bfd_byte *contents;
+ PTR external_relocs;
{
+ asection **symndx_to_section;
+ struct ecoff_link_hash_entry **sym_hashes;
+ bfd_vma gp;
+ bfd_boolean gp_undefined;
+ struct external_reloc *ext_rel;
+ struct external_reloc *ext_rel_end;
+ unsigned int i;
+ bfd_boolean got_lo;
+ struct internal_reloc lo_int_rel;
+ bfd_size_type amt;
+
+ BFD_ASSERT (input_bfd->xvec->byteorder
+ == output_bfd->xvec->byteorder);
+
+ /* We keep a table mapping the symndx found in an internal reloc to
+ the appropriate section. This is faster than looking up the
+ section by name each time. */
+ symndx_to_section = ecoff_data (input_bfd)->symndx_to_section;
+ if (symndx_to_section == (asection **) NULL)
+ {
+ amt = NUM_RELOC_SECTIONS * sizeof (asection *);
+ symndx_to_section = (asection **) bfd_alloc (input_bfd, amt);
+ if (!symndx_to_section)
+ return FALSE;
+
+ symndx_to_section[RELOC_SECTION_NONE] = NULL;
+ symndx_to_section[RELOC_SECTION_TEXT] =
+ bfd_get_section_by_name (input_bfd, ".text");
+ symndx_to_section[RELOC_SECTION_RDATA] =
+ bfd_get_section_by_name (input_bfd, ".rdata");
+ symndx_to_section[RELOC_SECTION_DATA] =
+ bfd_get_section_by_name (input_bfd, ".data");
+ symndx_to_section[RELOC_SECTION_SDATA] =
+ bfd_get_section_by_name (input_bfd, ".sdata");
+ symndx_to_section[RELOC_SECTION_SBSS] =
+ bfd_get_section_by_name (input_bfd, ".sbss");
+ symndx_to_section[RELOC_SECTION_BSS] =
+ bfd_get_section_by_name (input_bfd, ".bss");
+ symndx_to_section[RELOC_SECTION_INIT] =
+ bfd_get_section_by_name (input_bfd, ".init");
+ symndx_to_section[RELOC_SECTION_LIT8] =
+ bfd_get_section_by_name (input_bfd, ".lit8");
+ symndx_to_section[RELOC_SECTION_LIT4] =
+ bfd_get_section_by_name (input_bfd, ".lit4");
+ symndx_to_section[RELOC_SECTION_XDATA] = NULL;
+ symndx_to_section[RELOC_SECTION_PDATA] = NULL;
+ symndx_to_section[RELOC_SECTION_FINI] =
+ bfd_get_section_by_name (input_bfd, ".fini");
+ symndx_to_section[RELOC_SECTION_LITA] = NULL;
+ symndx_to_section[RELOC_SECTION_ABS] = NULL;
+
+ ecoff_data (input_bfd)->symndx_to_section = symndx_to_section;
+ }
- esymbol *sym = obj_symbols (abfd) + idx;
+ sym_hashes = ecoff_data (input_bfd)->sym_hashes;
- switch (class) {
+ gp = _bfd_get_gp_value (output_bfd);
+ if (gp == 0)
+ gp_undefined = TRUE;
+ else
+ gp_undefined = FALSE;
- case bfd_symclass_fcommon: return (sym->c.flags & BSF_FORT_COMM) != 0;
- case bfd_symclass_global: return (sym->c.flags & BSF_GLOBAL) != 0;
- case bfd_symclass_debugger: return (sym->c.flags & BSF_DEBUGGING) != 0;
- case bfd_symclass_undefined: return (sym->c.flags & BSF_UNDEFINED) != 0;
-
- default: return false;
- }
-}
+ got_lo = FALSE;
+ ext_rel = (struct external_reloc *) external_relocs;
+ ext_rel_end = ext_rel + input_section->reloc_count;
+ for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
+ {
+ struct internal_reloc int_rel;
+ bfd_boolean use_lo = FALSE;
+ bfd_vma addend;
+ reloc_howto_type *howto;
+ struct ecoff_link_hash_entry *h = NULL;
+ asection *s = NULL;
+ bfd_vma relocation;
+ bfd_reloc_status_type r;
+
+ if (! got_lo)
+ mips_ecoff_swap_reloc_in (input_bfd, (PTR) ext_rel, &int_rel);
+ else
+ {
+ int_rel = lo_int_rel;
+ got_lo = FALSE;
+ }
+ BFD_ASSERT (int_rel.r_type
+ < sizeof mips_howto_table / sizeof mips_howto_table[0]);
+ /* The REFHI reloc requires special handling. It must be followed
+ by a REFLO reloc, and the addend is formed from both relocs. */
+ if (int_rel.r_type == MIPS_R_REFHI)
+ {
+ struct external_reloc *lo_ext_rel;
+
+ /* As a GNU extension, permit an arbitrary number of REFHI
+ relocs before the REFLO reloc. This permits gcc to emit
+ the HI and LO relocs itself. */
+ for (lo_ext_rel = ext_rel + 1;
+ lo_ext_rel < ext_rel_end;
+ lo_ext_rel++)
+ {
+ mips_ecoff_swap_reloc_in (input_bfd, (PTR) lo_ext_rel,
+ &lo_int_rel);
+ if (lo_int_rel.r_type != int_rel.r_type)
+ break;
+ }
-static
-boolean
-ecoff_slurp_line_table (abfd, asect)
- bfd *abfd;
- asection *asect;
-{
- return true;
-}
+ if (lo_ext_rel < ext_rel_end
+ && lo_int_rel.r_type == MIPS_R_REFLO
+ && int_rel.r_extern == lo_int_rel.r_extern
+ && int_rel.r_symndx == lo_int_rel.r_symndx)
+ {
+ use_lo = TRUE;
+ if (lo_ext_rel == ext_rel + 1)
+ got_lo = TRUE;
+ }
+ }
-static boolean
-ecoff_slurp_symbol_table(abfd)
- bfd *abfd;
-{
- struct syment *native_symbols;
- esymbol *cached_area;
- char *string_table = (char *)NULL;
- unsigned int string_table_size;
- unsigned int number_of_symbols = 0;
- if (obj_symbols (abfd)) return true;
- bfd_seek(abfd, obj_sym_filepos(abfd), false);
- /* Read in the symbol table */
- native_symbols =
- (struct syment *)buy_and_read(abfd,
- obj_sym_filepos(abfd),
- false,
- bfd_get_symcount(abfd) * sizeof(struct syment));
- if (!native_symbols) {
- return false;
- }
-
-
- /* Allocate enough room for all the symbols in cached form */
- cached_area = (esymbol *)xmalloc(bfd_get_symcount(abfd) * sizeof(esymbol));
+ howto = &mips_howto_table[int_rel.r_type];
+ if (int_rel.r_extern)
+ {
+ h = sym_hashes[int_rel.r_symndx];
+ /* If h is NULL, that means that there is a reloc against an
+ external symbol which we thought was just a debugging
+ symbol. This should not happen. */
+ if (h == (struct ecoff_link_hash_entry *) NULL)
+ abort ();
+ }
+ else
+ {
+ if (int_rel.r_symndx < 0 || int_rel.r_symndx >= NUM_RELOC_SECTIONS)
+ s = NULL;
+ else
+ s = symndx_to_section[int_rel.r_symndx];
- {
+ if (s == (asection *) NULL)
+ abort ();
+ }
- esymbol *dst = cached_area;
- unsigned int last_native_index = bfd_get_symcount(abfd);
- unsigned int this_index = 0;
- while (this_index < last_native_index)
- {
- struct syment *src = native_symbols + this_index;
- if (src->n_zeroes == 0) {
- /* This symbol has a name in the string table */
- /* Which means that we'll have to read it in */
-
- /* Fetch the size of the string table which is straight after the
- * symbol table
- */
- if (string_table == (char *)NULL) {
- if (bfd_read(&string_table_size, sizeof(string_table_size), 1, abfd) !=
- sizeof(string_table_size)) {
- fatal("Corrupt coff format");
+ /* The GPREL reloc uses an addend: the difference in the GP
+ values. */
+ if (int_rel.r_type != MIPS_R_GPREL
+ && int_rel.r_type != MIPS_R_LITERAL)
+ addend = 0;
+ else
+ {
+ if (gp_undefined)
+ {
+ if (! ((*info->callbacks->reloc_dangerous)
+ (info, _("GP relative relocation used when GP not defined"),
+ input_bfd, input_section,
+ int_rel.r_vaddr - input_section->vma)))
+ return FALSE;
+ /* Only give the error once per link. */
+ gp = 4;
+ _bfd_set_gp_value (output_bfd, gp);
+ gp_undefined = FALSE;
}
- else {
- /* Read the string table */
- string_table =
- (char *)buy_and_read(abfd,0, true,
- string_table_size - sizeof(string_table_size)) ;
-
+ if (! int_rel.r_extern)
+ {
+ /* This is a relocation against a section. The current
+ addend in the instruction is the difference between
+ INPUT_SECTION->vma and the GP value of INPUT_BFD. We
+ must change this to be the difference between the
+ final definition (which will end up in RELOCATION)
+ and the GP value of OUTPUT_BFD (which is in GP). */
+ addend = ecoff_data (input_bfd)->gp - gp;
+ }
+ else if (! info->relocatable
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ /* This is a relocation against a defined symbol. The
+ current addend in the instruction is simply the
+ desired offset into the symbol (normally zero). We
+ are going to change this into a relocation against a
+ defined symbol, so we want the instruction to hold
+ the difference between the final definition of the
+ symbol (which will end up in RELOCATION) and the GP
+ value of OUTPUT_BFD (which is in GP). */
+ addend = - gp;
}
- }
+ else
+ {
+ /* This is a relocation against an undefined or common
+ symbol. The current addend in the instruction is
+ simply the desired offset into the symbol (normally
+ zero). We are generating relocatable output, and we
+ aren't going to define this symbol, so we just leave
+ the instruction alone. */
+ addend = 0;
+ }
+ }
+ if (info->relocatable)
+ {
+ /* We are generating relocatable output, and must convert
+ the existing reloc. */
+ if (int_rel.r_extern)
+ {
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && ! bfd_is_abs_section (h->root.u.def.section))
+ {
+ const char *name;
+
+ /* This symbol is defined in the output. Convert
+ the reloc from being against the symbol to being
+ against the section. */
+
+ /* Clear the r_extern bit. */
+ int_rel.r_extern = 0;
+
+ /* Compute a new r_symndx value. */
+ s = h->root.u.def.section;
+ name = bfd_get_section_name (output_bfd,
+ s->output_section);
+
+ int_rel.r_symndx = -1;
+ switch (name[1])
+ {
+ case 'b':
+ if (strcmp (name, ".bss") == 0)
+ int_rel.r_symndx = RELOC_SECTION_BSS;
+ break;
+ case 'd':
+ if (strcmp (name, ".data") == 0)
+ int_rel.r_symndx = RELOC_SECTION_DATA;
+ break;
+ case 'f':
+ if (strcmp (name, ".fini") == 0)
+ int_rel.r_symndx = RELOC_SECTION_FINI;
+ break;
+ case 'i':
+ if (strcmp (name, ".init") == 0)
+ int_rel.r_symndx = RELOC_SECTION_INIT;
+ break;
+ case 'l':
+ if (strcmp (name, ".lit8") == 0)
+ int_rel.r_symndx = RELOC_SECTION_LIT8;
+ else if (strcmp (name, ".lit4") == 0)
+ int_rel.r_symndx = RELOC_SECTION_LIT4;
+ break;
+ case 'r':
+ if (strcmp (name, ".rdata") == 0)
+ int_rel.r_symndx = RELOC_SECTION_RDATA;
+ break;
+ case 's':
+ if (strcmp (name, ".sdata") == 0)
+ int_rel.r_symndx = RELOC_SECTION_SDATA;
+ else if (strcmp (name, ".sbss") == 0)
+ int_rel.r_symndx = RELOC_SECTION_SBSS;
+ break;
+ case 't':
+ if (strcmp (name, ".text") == 0)
+ int_rel.r_symndx = RELOC_SECTION_TEXT;
+ break;
+ }
+
+ if (int_rel.r_symndx == -1)
+ abort ();
+
+ /* Add the section VMA and the symbol value. */
+ relocation = (h->root.u.def.value
+ + s->output_section->vma
+ + s->output_offset);
+
+ /* For a PC relative relocation, the object file
+ currently holds just the addend. We must adjust
+ by the address to get the right value. */
+ if (howto->pc_relative)
+ relocation -= int_rel.r_vaddr - input_section->vma;
+
+ h = NULL;
+ }
+ else
+ {
+ /* Change the symndx value to the right one for the
+ output BFD. */
+ int_rel.r_symndx = h->indx;
+ if (int_rel.r_symndx == -1)
+ {
+ /* This symbol is not being written out. */
+ if (! ((*info->callbacks->unattached_reloc)
+ (info, h->root.root.string, input_bfd,
+ input_section,
+ int_rel.r_vaddr - input_section->vma)))
+ return FALSE;
+ int_rel.r_symndx = 0;
+ }
+ relocation = 0;
+ }
+ }
+ else
+ {
+ /* This is a relocation against a section. Adjust the
+ value by the amount the section moved. */
+ relocation = (s->output_section->vma
+ + s->output_offset
+ - s->vma);
+ }
- dst->c.name = string_table + src->n_offset - 4;
- }
- else {
- /* Otherwise we have to buy somewhere for this name */
- dst->c.name = xmalloc (SYMNMLEN+1);
- strncpy(dst->c.name, src->n_name, SYMNMLEN);
- dst->c.name[SYMNMLEN+1] = '\0'; /* Be sure to terminate it */
- }
-
- /* We use the native name field to point to the cached field */
- src->n_zeroes = (long)dst;
- dst->c.section = section_from_bfd_index(abfd, src->n_scnum);
- switch (src->n_sclass)
- {
-#ifdef I960
- case C_LEAFPROC:
- dst->c.value = src->n_value - dst->c.section->vma;
- dst->c.flags = BSF_EXPORT | BSF_GLOBAL;
- dst->c.flags |= BSF_NOT_AT_END;
- break;
-
-#endif
-
- case C_EXT:
- if (src->n_scnum == 0) {
- if (src->n_value == 0)
+ relocation += addend;
+ addend = 0;
+
+ /* Adjust a PC relative relocation by removing the reference
+ to the original address in the section and including the
+ reference to the new address. */
+ if (howto->pc_relative)
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ /* Adjust the contents. */
+ if (relocation == 0)
+ r = bfd_reloc_ok;
+ else
+ {
+ if (int_rel.r_type != MIPS_R_REFHI)
+ r = _bfd_relocate_contents (howto, input_bfd, relocation,
+ (contents
+ + int_rel.r_vaddr
+ - input_section->vma));
+ else
{
- dst->c.flags = BSF_UNDEFINED;
+ mips_relocate_hi (&int_rel,
+ use_lo ? &lo_int_rel : NULL,
+ input_bfd, input_section, contents,
+ relocation);
+ r = bfd_reloc_ok;
}
- else {
- dst->c.flags = BSF_FORT_COMM;
- dst->c.value = src->n_value;
- }
}
- else {
- /* Base the value as an index from the base of the section */
- if (dst->c.section == (asection *)NULL)
+ /* Adjust the reloc address. */
+ int_rel.r_vaddr += (input_section->output_section->vma
+ + input_section->output_offset
+ - input_section->vma);
+
+ /* Save the changed reloc information. */
+ mips_ecoff_swap_reloc_out (input_bfd, &int_rel, (PTR) ext_rel);
+ }
+ else
+ {
+ /* We are producing a final executable. */
+ if (int_rel.r_extern)
+ {
+ /* This is a reloc against a symbol. */
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
{
- dst->c.flags = BSF_EXPORT | BSF_GLOBAL | BSF_ABSOLUTE;
- dst->c.value = src->n_value;
+ asection *hsec;
+
+ hsec = h->root.u.def.section;
+ relocation = (h->root.u.def.value
+ + hsec->output_section->vma
+ + hsec->output_offset);
}
- else
+ else
{
- dst->c.flags = BSF_EXPORT | BSF_GLOBAL;
- dst->c.value = src->n_value - dst->c.section->vma;
+ if (! ((*info->callbacks->undefined_symbol)
+ (info, h->root.root.string, input_bfd,
+ input_section,
+ int_rel.r_vaddr - input_section->vma, TRUE)))
+ return FALSE;
+ relocation = 0;
}
- if (ISFCN(src->n_type)) {
- /* A function ext does not go at the end of a file*/
- dst->c.flags |= BSF_NOT_AT_END;
- }
+ }
+ else
+ {
+ /* This is a reloc against a section. */
+ relocation = (s->output_section->vma
+ + s->output_offset
+ - s->vma);
+
+ /* A PC relative reloc is already correct in the object
+ file. Make it look like a pcrel_offset relocation by
+ adding in the start address. */
+ if (howto->pc_relative)
+ relocation += int_rel.r_vaddr;
+ }
+ if (int_rel.r_type != MIPS_R_REFHI)
+ r = _bfd_final_link_relocate (howto,
+ input_bfd,
+ input_section,
+ contents,
+ (int_rel.r_vaddr
+ - input_section->vma),
+ relocation,
+ addend);
+ else
+ {
+ mips_relocate_hi (&int_rel,
+ use_lo ? &lo_int_rel : NULL,
+ input_bfd, input_section, contents,
+ relocation);
+ r = bfd_reloc_ok;
}
+ }
- break;
- case C_STAT : /* static */
- case C_LABEL : /* label */
- dst->c.flags = BSF_LOCAL;
- /* Base the value as an index from the base of the section */
- dst->c.value = src->n_value - dst->c.section->vma;
- break;
-
- case C_MOS : /* member of structure */
- case C_EOS : /* end of structure */
- case C_REGPARM : /* register parameter */
- case C_REG : /* register variable */
- case 19 : /* Intel specific REGARG FIXME */
- case C_TPDEF : /* type definition */
-
- case C_ARG:
- case C_AUTO: /* automatic variable */
- case C_FIELD: /* bit field */
- case C_ENTAG : /* enumeration tag */
- case C_MOE : /* member of enumeration */
- case C_MOU : /* member of union */
- case C_UNTAG : /* union tag */
-
- dst->c.flags = BSF_DEBUGGING;
- dst->c.value = src->n_value;
- break;
-
- case C_FILE : /* file name */
- case C_STRTAG : /* structure tag */
- dst->c.flags = BSF_DEBUGGING;
- dst->c.value = src->n_value ;
-
- break;
- case C_BLOCK : /* ".bb" or ".eb" */
- case C_FCN : /* ".bf" or ".ef" */
- dst->c.flags = BSF_LOCAL;
- /* Base the value as an index from the base of the section */
- dst->c.value = src->n_value - dst->c.section->vma;
-
- break;
- case C_EFCN : /* physical end of function */
- case C_NULL:
- case C_EXTDEF : /* external definition */
- case C_ULABEL : /* undefined label */
- case C_USTATIC : /* undefined static */
- case C_LINE : /* line # reformatted as symbol table entry */
- case C_ALIAS : /* duplicate tag */
- case C_HIDDEN : /* ext symbol in dmert public lib */
-
- default:
-
- printf("SICK%d\n",src->n_sclass);
- dst->c.flags = BSF_DEBUGGING;
- dst->c.value = src->n_value ;
-
- break;
- }
-
-
-
-
- if (dst->c.flags == 0) fatal("OOOO dear");
-
- dst->native = src;
- dst->c.udata = 0;
- dst->c.lineno = (alent *)NULL;
- this_index += src->n_numaux + 1;
- dst++;
- number_of_symbols++;
- }
-
- }
- obj_symbols(abfd) = cached_area;
- obj_raw_syments(abfd) = native_symbols;
- bfd_get_symcount(abfd) = number_of_symbols;
-
- /* Slurp the line tables for each section too */
- {
- asection *p;
- p = abfd->sections;
- while (p) {
- ecoff_slurp_line_table(abfd, p);
- p =p->next;
+ /* MIPS_R_JMPADDR requires peculiar overflow detection. The
+ instruction provides a 28 bit address (the two lower bits are
+ implicit zeroes) which is combined with the upper four bits
+ of the instruction address. */
+ if (r == bfd_reloc_ok
+ && int_rel.r_type == MIPS_R_JMPADDR
+ && (((relocation
+ + addend
+ + (int_rel.r_extern ? 0 : s->vma))
+ & 0xf0000000)
+ != ((input_section->output_section->vma
+ + input_section->output_offset
+ + (int_rel.r_vaddr - input_section->vma))
+ & 0xf0000000)))
+ r = bfd_reloc_overflow;
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ default:
+ case bfd_reloc_outofrange:
+ abort ();
+ case bfd_reloc_overflow:
+ {
+ const char *name;
+
+ if (int_rel.r_extern)
+ name = NULL;
+ else
+ name = bfd_section_name (input_bfd, s);
+ if (! ((*info->callbacks->reloc_overflow)
+ (info, (h ? &h->root : NULL), name, howto->name,
+ (bfd_vma) 0, input_bfd, input_section,
+ int_rel.r_vaddr - input_section->vma)))
+ return FALSE;
+ }
+ break;
+ }
+ }
}
- }
- return true;
-}
-unsigned int
-ecoff_get_symtab_upper_bound (abfd)
- bfd *abfd;
-{
- if (!ecoff_slurp_symbol_table (abfd)) return 0;
-
- return (bfd_get_symcount (abfd)+1) * (sizeof (esymbol *));
-}
-
-
-unsigned int
-ecoff_get_symtab(abfd, alocation)
-bfd *abfd;
-asymbol **alocation;
-{
- unsigned int counter = 0;
- esymbol *symbase;
- esymbol **location = (esymbol **)(alocation);
-
- if (!ecoff_slurp_symbol_table (abfd)) return 0;
-
- for (symbase = obj_symbols (abfd); counter++ < bfd_get_symcount (abfd);)
- *(location++) = symbase++;
- *location++ =0;
- return counter;
+ return TRUE;
}
+\f
+/* This is the ECOFF backend structure. The backend field of the
+ target vector points to this. */
-unsigned int
-ecoff_get_reloc_upper_bound (abfd, asect)
- bfd *abfd;
- sec_ptr asect;
+static const struct ecoff_backend_data mips_ecoff_backend_data =
{
- if (bfd_get_format (abfd) != bfd_object) {
- bfd_error = invalid_operation;
- return 0;
- }
-
- return (asect->reloc_count + 1) * sizeof(arelent *);
-}
-
+ /* COFF backend structure. */
+ {
+ (void (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR))) bfd_void, /* aux_in */
+ (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_in */
+ (void (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_in */
+ (unsigned (*) PARAMS ((bfd *,PTR,int,int,int,int,PTR)))bfd_void,/*aux_out*/
+ (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* sym_out */
+ (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* lineno_out */
+ (unsigned (*) PARAMS ((bfd *,PTR,PTR))) bfd_void, /* reloc_out */
+ mips_ecoff_swap_filehdr_out, mips_ecoff_swap_aouthdr_out,
+ mips_ecoff_swap_scnhdr_out,
+ FILHSZ, AOUTSZ, SCNHSZ, 0, 0, 0, 0, FILNMLEN, TRUE,
+ ECOFF_NO_LONG_SECTION_NAMES, 4, FALSE, 2,
+ mips_ecoff_swap_filehdr_in, mips_ecoff_swap_aouthdr_in,
+ mips_ecoff_swap_scnhdr_in, NULL,
+ mips_ecoff_bad_format_hook, _bfd_ecoff_set_arch_mach_hook,
+ _bfd_ecoff_mkobject_hook, _bfd_ecoff_styp_to_sec_flags,
+ _bfd_ecoff_set_alignment_hook, _bfd_ecoff_slurp_symbol_table,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL
+ },
+ /* Supported architecture. */
+ bfd_arch_mips,
+ /* Initial portion of armap string. */
+ "__________",
+ /* The page boundary used to align sections in a demand-paged
+ executable file. E.g., 0x1000. */
+ 0x1000,
+ /* TRUE if the .rdata section is part of the text segment, as on the
+ Alpha. FALSE if .rdata is part of the data segment, as on the
+ MIPS. */
+ FALSE,
+ /* Bitsize of constructor entries. */
+ 32,
+ /* Reloc to use for constructor entries. */
+ &mips_howto_table[MIPS_R_REFWORD],
+ {
+ /* Symbol table magic number. */
+ magicSym,
+ /* Alignment of debugging information. E.g., 4. */
+ 4,
+ /* Sizes of external symbolic information. */
+ sizeof (struct hdr_ext),
+ sizeof (struct dnr_ext),
+ sizeof (struct pdr_ext),
+ sizeof (struct sym_ext),
+ sizeof (struct opt_ext),
+ sizeof (struct fdr_ext),
+ sizeof (struct rfd_ext),
+ sizeof (struct ext_ext),
+ /* Functions to swap in external symbolic data. */
+ ecoff_swap_hdr_in,
+ ecoff_swap_dnr_in,
+ ecoff_swap_pdr_in,
+ ecoff_swap_sym_in,
+ ecoff_swap_opt_in,
+ ecoff_swap_fdr_in,
+ ecoff_swap_rfd_in,
+ ecoff_swap_ext_in,
+ _bfd_ecoff_swap_tir_in,
+ _bfd_ecoff_swap_rndx_in,
+ /* Functions to swap out external symbolic data. */
+ ecoff_swap_hdr_out,
+ ecoff_swap_dnr_out,
+ ecoff_swap_pdr_out,
+ ecoff_swap_sym_out,
+ ecoff_swap_opt_out,
+ ecoff_swap_fdr_out,
+ ecoff_swap_rfd_out,
+ ecoff_swap_ext_out,
+ _bfd_ecoff_swap_tir_out,
+ _bfd_ecoff_swap_rndx_out,
+ /* Function to read in symbolic data. */
+ _bfd_ecoff_slurp_symbolic_info
+ },
+ /* External reloc size. */
+ RELSZ,
+ /* Reloc swapping functions. */
+ mips_ecoff_swap_reloc_in,
+ mips_ecoff_swap_reloc_out,
+ /* Backend reloc tweaking. */
+ mips_adjust_reloc_in,
+ mips_adjust_reloc_out,
+ /* Relocate section contents while linking. */
+ mips_relocate_section,
+ /* Do final adjustments to filehdr and aouthdr. */
+ NULL,
+ /* Read an element from an archive at a given file position. */
+ _bfd_get_elt_at_filepos
+};
+/* Looking up a reloc type is MIPS specific. */
+#define _bfd_ecoff_bfd_reloc_type_lookup mips_bfd_reloc_type_lookup
+#define _bfd_ecoff_bfd_reloc_name_lookup mips_bfd_reloc_name_lookup
+/* Getting relocated section contents is generic. */
+#define _bfd_ecoff_bfd_get_relocated_section_contents \
+ bfd_generic_get_relocated_section_contents
-boolean
-ecoff_slurp_reloc_table (abfd, asect)
- bfd *abfd;
- sec_ptr asect;
-{
- struct reloc *native_relocs;
- arelent *reloc_cache;
+/* Handling file windows is generic. */
+#define _bfd_ecoff_get_section_contents_in_window \
+ _bfd_generic_get_section_contents_in_window
- if (asect->relocation) return true;
- if (asect->reloc_count ==0) return true;
- if (!ecoff_slurp_symbol_table (abfd)) return false;
+/* Relaxing sections is MIPS specific. */
+#define _bfd_ecoff_bfd_relax_section bfd_generic_relax_section
- native_relocs = (struct reloc *)buy_and_read(abfd,
- asect->rel_filepos,
- false,
- sizeof(struct reloc) * asect->reloc_count);
- reloc_cache = (arelent *)xmalloc(asect->reloc_count * sizeof(arelent ));
+/* GC of sections is not done. */
+#define _bfd_ecoff_bfd_gc_sections bfd_generic_gc_sections
- {
+/* Merging of sections is not done. */
+#define _bfd_ecoff_bfd_merge_sections bfd_generic_merge_sections
- unsigned int counter = 0;
- arelent *cache_ptr = reloc_cache;
- struct reloc *src = native_relocs;
- while (counter < asect->reloc_count)
- {
- cache_ptr->address = src->r_vaddr - asect->original_vma;
- cache_ptr->sym = (asymbol *)(src->r_symndx +
- obj_raw_syments (abfd))->n_zeroes;
- /* The symbols that we have read in have been relocated as if their
- * sections started at 0. But the offsets refering to the symbols
- * in the raw data have not been modified, so we have to have
- * a negative addend to compensate
- */
- if (cache_ptr->sym->section) {
- cache_ptr->addend = - cache_ptr->sym->section->original_vma;
- }
- else {
- /* If the symbol doesn't have a section then it hasn't been relocated,
- * so we don't have to fix it
- */
- cache_ptr->addend = 0;
- }
+#define _bfd_ecoff_bfd_is_group_section bfd_generic_is_group_section
+#define _bfd_ecoff_bfd_discard_group bfd_generic_discard_group
+#define _bfd_ecoff_section_already_linked \
+ _bfd_generic_section_already_linked
- cache_ptr->section = 0;
-#if I960
- cache_ptr->howto = howto_table + src->r_type;
-#endif
-#if M88
- if (src->r_type >= R_PCR16L && src->r_type <= R_VRT32)
- {
- cache_ptr->howto = howto_table + src->r_type - R_PCR16L;
- }
- else
- {
- fatal("unrecognised reloc type %d\n", src->r_type);
- }
-#endif
- cache_ptr++;
- src++;
- counter++;
- }
-
- }
-
- free (native_relocs);
- asect->relocation = reloc_cache;
- return true;
-}
+extern const bfd_target ecoff_big_vec;
+const bfd_target ecoff_little_vec =
+{
+ "ecoff-littlemips", /* name */
+ bfd_target_ecoff_flavour,
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_LITTLE, /* header byte order is little */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+
+ {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, _bfd_dummy_target},
+ {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
+ {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
+ BFD_JUMP_TABLE_COPY (_bfd_ecoff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
+ BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
+ BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
+ BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
+ BFD_JUMP_TABLE_LINK (_bfd_ecoff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ & ecoff_big_vec,
+
+ (PTR) &mips_ecoff_backend_data
+};
-/* This is stupid. This function should be a boolean predicate */
-unsigned int
-ecoff_canonicalize_reloc (abfd, section, relptr)
- bfd *abfd;
- sec_ptr section;
- arelent **relptr;
+const bfd_target ecoff_big_vec =
{
- return 0;
-}
+ "ecoff-bigmips", /* name */
+ bfd_target_ecoff_flavour,
+ BFD_ENDIAN_BIG, /* data byte order is big */
+ BFD_ENDIAN_BIG, /* header byte order is big */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16,
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16,
+ {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, _bfd_dummy_target},
+ {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
+ {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
+ BFD_JUMP_TABLE_COPY (_bfd_ecoff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
+ BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
+ BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
+ BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
+ BFD_JUMP_TABLE_LINK (_bfd_ecoff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ & ecoff_little_vec,
+
+ (PTR) &mips_ecoff_backend_data
+};
-bfd_target ecoff_little_vec =
- {"ecoff-littlemips", /* name */
- false, /* data byte order is little */
- false, /* header byte order is little */
-
- (HAS_RELOC | EXEC_P | /* object flags */
- HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
-
- (SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
- 0, /* valid reloc types */
- '/', /* ar_pad_char */
- 15, /* ar_max_namelen */
- ecoff_close_and_cleanup, /* _close_and_cleanup */
- ecoff_set_section_contents, /* bfd_set_section_contents */
- ecoff_new_section_hook, /* new_section_hook */
- _bfd_dummy_core_file_failing_command, /* _core_file_failing_command */
- _bfd_dummy_core_file_failing_signal, /* _core_file_failing_signal */
- _bfd_dummy_core_file_matches_executable_p, /* _core_file_matches_ex...p */
-
- bfd_slurp_coff_armap, /* bfd_slurp_armap */
- _bfd_slurp_extended_name_table, /* bfd_slurp_extended_name_table*/
- bfd_dont_truncate_arname, /* bfd_truncate_arname */
-
- ecoff_get_symtab_upper_bound, /* get_symtab_upper_bound */
- ecoff_get_symtab, /* canonicalize_symtab */
- (void (*)())bfd_false, /* bfd_reclaim_symbol_table */
- ecoff_get_reloc_upper_bound, /* get_reloc_upper_bound */
- ecoff_canonicalize_reloc, /* bfd_canonicalize_reloc */
- (void (*)())bfd_false, /* bfd_reclaim_reloc */
-
- ecoff_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */
- ecoff_get_first_symbol, /* bfd_get_first_symbol */
- ecoff_get_next_symbol, /* bfd_get_next_symbol */
- ecoff_classify_symbol, /* bfd_classify_symbol */
- ecoff_symbol_hasclass, /* bfd_symbol_hasclass */
- ecoff_symbol_name, /* bfd_symbol_name */
- ecoff_symbol_value, /* bfd_symbol_value */
-
- _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* data */
- _do_getllong, _do_putllong, _do_getlshort, _do_putlshort, /* hdrs */
-
- {_bfd_dummy_target, ecoff_object_p, /* bfd_check_format */
- bfd_generic_archive_p, _bfd_dummy_target},
- {bfd_false, ecoff_mkobject, bfd_false, /* bfd_set_format */
- bfd_false},
- ecoff_make_empty_symbol,
-
-
- };
-
-bfd_target ecoff_big_vec =
- {"ecoff-bigmips", /* name */
- true, /* data byte order is big */
- true, /* header byte order is big */
-
- (HAS_RELOC | EXEC_P | /* object flags */
- HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
-
- (SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
- 0, /* valid reloc types */
- '/', /* ar_pad_char */
- 15, /* ar_max_namelen */
- ecoff_close_and_cleanup, /* _close_and_cleanup */
- ecoff_set_section_contents, /* bfd_set_section_contents */
- ecoff_new_section_hook, /* new_section_hook */
- _bfd_dummy_core_file_failing_command, /* _core_file_failing_command */
- _bfd_dummy_core_file_failing_signal, /* _core_file_failing_signal */
- _bfd_dummy_core_file_matches_executable_p, /* _core_file_matches_ex...p */
-
- bfd_slurp_coff_armap, /* bfd_slurp_armap */
- _bfd_slurp_extended_name_table, /* bfd_slurp_extended_name_table*/
- bfd_dont_truncate_arname, /* bfd_truncate_arname */
-
- ecoff_get_symtab_upper_bound, /* get_symtab_upper_bound */
- ecoff_get_symtab, /* canonicalize_symtab */
- (void (*)())bfd_false, /* bfd_reclaim_symbol_table */
- ecoff_get_reloc_upper_bound, /* get_reloc_upper_bound */
- ecoff_canonicalize_reloc, /* bfd_canonicalize_reloc */
- (void (*)())bfd_false, /* bfd_reclaim_reloc */
-
- ecoff_get_symcount_upper_bound, /* bfd_get_symcount_upper_bound */
- ecoff_get_first_symbol, /* bfd_get_first_symbol */
- ecoff_get_next_symbol, /* bfd_get_next_symbol */
- ecoff_classify_symbol, /* bfd_classify_symbol */
- ecoff_symbol_hasclass, /* bfd_symbol_hasclass */
- ecoff_symbol_name, /* bfd_symbol_name */
- ecoff_symbol_value, /* bfd_symbol_value */
-
- _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* data */
- _do_getblong, _do_putblong, _do_getbshort, _do_putbshort, /* hdrs */
-
- {_bfd_dummy_target, ecoff_object_p, /* bfd_check_format */
- bfd_generic_archive_p, _bfd_dummy_target},
- {bfd_false, ecoff_mkobject, bfd_false, /* bfd_set_format */
- bfd_false},
- ecoff_make_empty_symbol,
-
-
- };
-
-#endif /* ECOFF_BFD */
+const bfd_target ecoff_biglittle_vec =
+{
+ "ecoff-biglittlemips", /* name */
+ bfd_target_ecoff_flavour,
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_BIG, /* header byte order is big */
+
+ (HAS_RELOC | EXEC_P | /* object flags */
+ HAS_LINENO | HAS_DEBUG |
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_DATA),
+ 0, /* leading underscore */
+ ' ', /* ar_pad_char */
+ 15, /* ar_max_namelen */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+ bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+ bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
+
+ {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
+ bfd_generic_archive_p, _bfd_dummy_target},
+ {bfd_false, _bfd_ecoff_mkobject, /* bfd_set_format */
+ _bfd_generic_mkarchive, bfd_false},
+ {bfd_false, _bfd_ecoff_write_object_contents, /* bfd_write_contents */
+ _bfd_write_archive_contents, bfd_false},
+
+ BFD_JUMP_TABLE_GENERIC (_bfd_ecoff),
+ BFD_JUMP_TABLE_COPY (_bfd_ecoff),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_ecoff),
+ BFD_JUMP_TABLE_SYMBOLS (_bfd_ecoff),
+ BFD_JUMP_TABLE_RELOCS (_bfd_ecoff),
+ BFD_JUMP_TABLE_WRITE (_bfd_ecoff),
+ BFD_JUMP_TABLE_LINK (_bfd_ecoff),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ NULL,
+
+ (PTR) &mips_ecoff_backend_data
+};