/* MIPS-specific support for 32-bit ELF
- Copyright 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
asection *section,
bfd *output_bfd,
char **error));
-static const struct reloc_howto_struct *bfd_elf32_bfd_reloc_type_lookup
+static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void mips_info_to_howto_rel
PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
static void mips_elf_symbol_processing PARAMS ((bfd *, asymbol *));
static boolean mips_elf_read_ecoff_info
PARAMS ((bfd *, asection *, struct ecoff_debug_info *));
+static boolean mips_elf_is_local_label
+ PARAMS ((bfd *, asymbol *));
+static boolean mips_elf_find_nearest_line
+ PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **,
+ const char **, unsigned int *));
static struct bfd_hash_entry *mips_elf_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *mips_elf_link_hash_table_create
R_MIPS_GPREL16, R_MIPS_LITERAL,
R_MIPS_GOT16, R_MIPS_PC16,
R_MIPS_CALL16, R_MIPS_GPREL32,
+ /* The remaining relocs are defined on Irix, although they are not
+ in the MIPS ELF ABI. */
+ R_MIPS_UNUSED1, R_MIPS_UNUSED2,
+ R_MIPS_UNUSED3,
+ R_MIPS_SHIFT5, R_MIPS_SHIFT6,
+ R_MIPS_64, R_MIPS_GOT_DISP,
+ R_MIPS_GOT_PAGE, R_MIPS_GOT_OFST,
+ R_MIPS_GOT_HI16, R_MIPS_GOT_LO16,
+ R_MIPS_SUB, R_MIPS_INSERT_A,
+ R_MIPS_INSERT_B, R_MIPS_DELETE,
+ R_MIPS_HIGHER, R_MIPS_HIGHEST,
+ R_MIPS_CALL_HI16, R_MIPS_CALL_LO16,
R_MIPS_max
};
true, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* The remaining relocs are defined on Irix 5, although they are
+ not defined by the ABI. */
+ { 13 },
+ { 14 },
+ { 15 },
+
+ /* A 5 bit shift field. */
+ HOWTO (R_MIPS_SHIFT5, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 5, /* bitsize */
+ false, /* pc_relative */
+ 6, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_SHIFT5", /* name */
+ true, /* partial_inplace */
+ 0x000007c0, /* src_mask */
+ 0x000007c0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* A 6 bit shift field. */
+ /* FIXME: This is not handled correctly; a special function is
+ needed to put the most significant bit in the right place. */
+ HOWTO (R_MIPS_SHIFT6, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 6, /* bitsize */
+ false, /* pc_relative */
+ 6, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_SHIFT6", /* name */
+ true, /* partial_inplace */
+ 0x000007c4, /* src_mask */
+ 0x000007c4, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* A 64 bit relocation. Presumably not used in 32 bit ELF. */
+ { R_MIPS_64 },
+
+ /* Displacement in the global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_GOT_DISP, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_GOT_DISP", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Displacement to page pointer in the global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_GOT_PAGE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_GOT_PAGE", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Offset from page pointer in the global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_GOT_OFST, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_GOT_OFST", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* High 16 bits of displacement in global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_GOT_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_GOT_HI16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_GOT_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_GOT_LO16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 64 bit subtraction. Presumably not used in 32 bit ELF. */
+ { R_MIPS_SUB },
+
+ /* Used to cause the linker to insert and delete instructions? */
+ { R_MIPS_INSERT_A },
+ { R_MIPS_INSERT_B },
+ { R_MIPS_DELETE },
+
+ /* Get the higher values of a 64 bit addend. Presumably not used in
+ 32 bit ELF. */
+ { R_MIPS_HIGHER },
+ { R_MIPS_HIGHEST },
+
+ /* High 16 bits of displacement in global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_CALL_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_CALL_HI16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* Low 16 bits of displacement in global offset table. */
+ /* FIXME: Not handled correctly. */
+ HOWTO (R_MIPS_CALL_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS_CALL_LO16", /* name */
+ true, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
false) /* pcrel_offset */
};
cleverly because the entries in the .lit8 and .lit4 sections can be
merged. */
+static bfd_reloc_status_type gprel16_with_gp PARAMS ((bfd *, asymbol *,
+ arelent *, asection *,
+ boolean, PTR, bfd_vma));
+
static bfd_reloc_status_type
mips_elf_gprel16_reloc (abfd,
reloc_entry,
char **error_message;
{
boolean relocateable;
- 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
&& relocateable == false)
return bfd_reloc_undefined;
+ /* Some of the code below assumes the output bfd is ELF too. */
+ if (output_bfd->xvec->flavour != bfd_target_elf_flavour)
+ abort ();
+
/* 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 ELF
}
}
+ return gprel16_with_gp (abfd, symbol, reloc_entry, input_section,
+ relocateable, data, elf_gp (output_bfd));
+}
+
+static bfd_reloc_status_type
+gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
+ gp)
+ bfd *abfd;
+ asymbol *symbol;
+ arelent *reloc_entry;
+ asection *input_section;
+ boolean relocateable;
+ PTR data;
+ bfd_vma gp;
+{
+ bfd_vma relocation;
+ unsigned long insn;
+ unsigned long val;
+
if (bfd_is_com_section (symbol->section))
relocation = 0;
else
an external symbol. */
if (relocateable == false
|| (symbol->flags & BSF_SECTION_SYM) != 0)
- val += relocation - elf_gp (output_bfd);
+ val += relocation - gp;
insn = (insn &~ 0xffff) | (val & 0xffff);
bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address);
/* Given a BFD reloc type, return a howto structure. */
-static const struct reloc_howto_struct *
+static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup (abfd, code)
bfd *abfd;
bfd_reloc_code_real_type code;
/* Irix 5 is broken. Object file symbol tables are not always
sorted correctly such that local symbols precede global symbols,
- and the sh_info field in the symbol table is not always right.
- We try to quickly check whether the symbol table is broken for
- this BFD, and, if it is, we set elf_bad_symtab in tdata. */
- if (elf_onesymtab (abfd) != 0)
- {
- Elf_Internal_Shdr *symtab_hdr;
- Elf32_External_Sym esym;
-
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- if (bfd_seek (abfd,
- (symtab_hdr->sh_offset
- + symtab_hdr->sh_size
- - sizeof (Elf32_External_Sym)),
- SEEK_SET) != 0
- || (bfd_read ((PTR) &esym, 1, sizeof (Elf32_External_Sym), abfd)
- != sizeof (Elf32_External_Sym)))
- return false;
- if (ELF_ST_BIND (bfd_h_get_8 (abfd, (bfd_byte *) esym.st_info))
- == STB_LOCAL)
- elf_bad_symtab (abfd) = true;
- }
+ and the sh_info field in the symbol table is not always right. */
+ elf_bad_symtab (abfd) = true;
return true;
}
if (strcmp (name, ".liblist") != 0)
return false;
break;
+ case SHT_MIPS_MSYM:
+ if (strcmp (name, ".msym") != 0)
+ return false;
+ break;
case SHT_MIPS_CONFLICT:
if (strcmp (name, ".conflict") != 0)
return false;
if (strcmp (name, ".options") != 0)
return false;
break;
+ case SHT_MIPS_DWARF:
+ if (strncmp (name, ".debug_", sizeof ".debug_" - 1) != 0)
+ return false;
+ break;
+ case SHT_MIPS_EVENTS:
+ if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) != 0)
+ return false;
+ break;
default:
return false;
}
hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib);
/* FIXME: Set the sh_link field. */
}
+ else if (strcmp (name, ".msym") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_MSYM;
+ hdr->sh_entsize = 8;
+ /* FIXME: Set the sh_info field. */
+ }
else if (strcmp (name, ".conflict") == 0)
hdr->sh_type = SHT_MIPS_CONFLICT;
else if (strncmp (name, ".gptab.", sizeof ".gptab." - 1) == 0)
hdr->sh_type = SHT_MIPS_OPTIONS;
hdr->sh_entsize = 1;
}
+ else if (strncmp (name, ".debug_", sizeof ".debug_" - 1) == 0)
+ hdr->sh_type = SHT_MIPS_DWARF;
+ else if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) == 0)
+ hdr->sh_type = SHT_MIPS_EVENTS;
return true;
}
swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
- ext_hdr = (char *) malloc (swap->external_hdr_size);
+ ext_hdr = (char *) malloc ((size_t) swap->external_hdr_size);
if (ext_hdr == NULL && swap->external_hdr_size != 0)
{
bfd_set_error (bfd_error_no_memory);
debug->ptr = NULL; \
else \
{ \
- debug->ptr = (type) malloc (size * symhdr->count); \
+ debug->ptr = (type) malloc ((size_t) (size * symhdr->count)); \
if (debug->ptr == NULL) \
{ \
bfd_set_error (bfd_error_no_memory); \
free (debug->external_ext);
return false;
}
+\f
+/* MIPS ELF local labels start with '$', not 'L'. */
+
+/*ARGSUSED*/
+static boolean
+mips_elf_is_local_label (abfd, symbol)
+ bfd *abfd;
+ asymbol *symbol;
+{
+ return symbol->name[0] == '$';
+}
+
+/* MIPS ELF uses a special find_nearest_line routine in order the
+ handle the ECOFF debugging information. */
+
+struct mips_elf_find_line
+{
+ struct ecoff_debug_info d;
+ struct ecoff_find_line i;
+};
+static boolean
+mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+ functionname_ptr, line_ptr)
+ bfd *abfd;
+ asection *section;
+ asymbol **symbols;
+ bfd_vma offset;
+ const char **filename_ptr;
+ const char **functionname_ptr;
+ unsigned int *line_ptr;
+{
+ asection *msec;
+
+ msec = bfd_get_section_by_name (abfd, ".mdebug");
+ if (msec != NULL)
+ {
+ struct mips_elf_find_line *fi;
+ const struct ecoff_debug_swap * const swap =
+ get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+
+ fi = elf_tdata (abfd)->find_line_info;
+ if (fi == NULL)
+ {
+ bfd_size_type external_fdr_size;
+ char *fraw_src;
+ char *fraw_end;
+ struct fdr *fdr_ptr;
+
+ fi = ((struct mips_elf_find_line *)
+ bfd_alloc (abfd, sizeof (struct mips_elf_find_line)));
+ if (fi == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+
+ memset (fi, 0, sizeof (struct mips_elf_find_line));
+
+ if (! mips_elf_read_ecoff_info (abfd, msec, &fi->d))
+ return false;
+
+ /* Swap in the FDR information. */
+ fi->d.fdr = ((struct fdr *)
+ bfd_alloc (abfd,
+ (fi->d.symbolic_header.ifdMax *
+ sizeof (struct fdr))));
+ if (fi->d.fdr == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ external_fdr_size = swap->external_fdr_size;
+ fdr_ptr = fi->d.fdr;
+ fraw_src = (char *) fi->d.external_fdr;
+ fraw_end = (fraw_src
+ + fi->d.symbolic_header.ifdMax * external_fdr_size);
+ for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
+ (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
+
+ elf_tdata (abfd)->find_line_info = fi;
+
+ /* Note that we don't bother to ever free this information.
+ find_nearest_line is either called all the time, as in
+ objdump -l, so the information should be saved, or it is
+ rarely called, as in ld error messages, so the memory
+ wasted is unimportant. Still, it would probably be a
+ good idea for free_cached_info to throw it away. */
+ }
+
+ if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
+ &fi->i, filename_ptr, functionname_ptr,
+ line_ptr))
+ return true;
+ }
+
+ /* Fall back on the generic ELF find_nearest_line routine. */
+
+ return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr);
+}
+\f
/* The MIPS ELF linker needs additional information for each symbol in
the global hash table. */
h->esym.asym.value = 0;
h->esym.asym.st = stGlobal;
- if (h->root.root.type != bfd_link_hash_defined)
+ if (h->root.root.type != bfd_link_hash_defined
+ && h->root.root.type != bfd_link_hash_defweak)
h->esym.asym.sc = scAbs;
else
{
h->esym.asym.index = indexNil;
}
+ if (h->root.root.type == bfd_link_hash_common)
+ h->esym.asym.value = h->root.root.u.c.size;
+ else if (h->root.root.type == bfd_link_hash_defined
+ || h->root.root.type == bfd_link_hash_defweak)
+ {
+ asection *sec;
+
+ if (h->esym.asym.sc == scCommon)
+ h->esym.asym.sc = scBss;
+ else if (h->esym.asym.sc == scSCommon)
+ h->esym.asym.sc = scSBss;
+
+ sec = h->root.root.u.def.section;
+ h->esym.asym.value = (h->root.root.u.def.value
+ + sec->output_offset
+ + sec->output_section->vma);
+ }
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
h->root.root.root.string,
input_section = p->u.indirect.section;
input_bfd = input_section->owner;
- BFD_ASSERT (input_section->_raw_size
- == sizeof (Elf32_External_RegInfo));
+
+ /* The linker emulation code has probably clobbered the
+ size to be zero bytes. */
+ if (input_section->_raw_size == 0)
+ input_section->_raw_size = sizeof (Elf32_External_RegInfo);
+
if (! bfd_get_section_contents (input_bfd, input_section,
(PTR) &ext,
(file_ptr) 0,
indx = r_symndx - extsymoff;
h = elf_sym_hashes (input_bfd)[indx];
- if (h->root.type == bfd_link_hash_defined)
+ if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
{
sec = h->root.u.def.section;
relocation = (h->root.u.def.value
+ sec->output_section->vma
+ sec->output_offset);
}
- else if (h->root.type == bfd_link_hash_weak)
+ else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
else
{
name = h->root.root.string;
else
{
- name = elf_string_from_elf_section (input_bfd,
- symtab_hdr->sh_link,
- sym->st_name);
+ name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
if (name == NULL)
return false;
if (*name == '\0')
return true;
}
\f
+/* This is almost identical to bfd_generic_get_... except that some
+ MIPS relocations need to be handled specially. Sigh. */
+static bfd_byte *
+elf32_mips_get_relocated_section_contents (abfd, link_info, link_order, data,
+ relocateable, symbols)
+ bfd *abfd;
+ struct bfd_link_info *link_info;
+ struct bfd_link_order *link_order;
+ bfd_byte *data;
+ boolean relocateable;
+ asymbol **symbols;
+{
+ /* Get enough memory to hold the stuff */
+ bfd *input_bfd = link_order->u.indirect.section->owner;
+ asection *input_section = link_order->u.indirect.section;
+
+ long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
+ arelent **reloc_vector = NULL;
+ long reloc_count;
+
+ if (reloc_size < 0)
+ goto error_return;
+
+ reloc_vector = (arelent **) malloc (reloc_size);
+ if (reloc_vector == NULL && reloc_size != 0)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto error_return;
+ }
+
+ /* read in the section */
+ if (!bfd_get_section_contents (input_bfd,
+ input_section,
+ (PTR) data,
+ 0,
+ input_section->_raw_size))
+ goto error_return;
+
+ /* We're not relaxing the section, so just copy the size info */
+ input_section->_cooked_size = input_section->_raw_size;
+ input_section->reloc_done = true;
+
+ reloc_count = bfd_canonicalize_reloc (input_bfd,
+ input_section,
+ reloc_vector,
+ symbols);
+ if (reloc_count < 0)
+ goto error_return;
+
+ if (reloc_count > 0)
+ {
+ arelent **parent;
+ /* for mips */
+ int gp_found;
+ bfd_vma gp = 0x12345678; /* initialize just to shut gcc up */
+
+ {
+ struct bfd_hash_entry *h;
+ struct bfd_link_hash_entry *lh;
+ /* Skip all this stuff if we aren't mixing formats. */
+ if (abfd && input_bfd
+ && abfd->xvec == input_bfd->xvec)
+ lh = 0;
+ else
+ {
+ h = bfd_hash_lookup (&link_info->hash->table, "_gp", false, false);
+ lh = (struct bfd_link_hash_entry *) h;
+ }
+ lookup:
+ if (lh)
+ {
+ switch (lh->type)
+ {
+ case bfd_link_hash_undefined:
+ case bfd_link_hash_undefweak:
+ case bfd_link_hash_common:
+ gp_found = 0;
+ break;
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ gp_found = 1;
+ gp = lh->u.def.value;
+ break;
+ case bfd_link_hash_indirect:
+ case bfd_link_hash_warning:
+ lh = lh->u.i.link;
+ /* @@FIXME ignoring warning for now */
+ goto lookup;
+ case bfd_link_hash_new:
+ default:
+ abort ();
+ }
+ }
+ else
+ gp_found = 0;
+ }
+ /* end mips */
+ for (parent = reloc_vector; *parent != (arelent *) NULL;
+ parent++)
+ {
+ char *error_message = (char *) NULL;
+ bfd_reloc_status_type r;
+
+ /* Specific to MIPS: Deal with relocation types that require
+ knowing the gp of the output bfd. */
+ asymbol *sym = *(*parent)->sym_ptr_ptr;
+ if (bfd_is_abs_section (sym->section) && abfd)
+ {
+ /* The special_function wouldn't get called anyways. */
+ }
+ else if (!gp_found)
+ {
+ /* The gp isn't there; let the special function code
+ fall over on its own. */
+ }
+ else if ((*parent)->howto->special_function == mips_elf_gprel16_reloc)
+ {
+ /* bypass special_function call */
+ r = gprel16_with_gp (input_bfd, sym, *parent, input_section,
+ relocateable, (PTR) data, gp);
+ goto skip_bfd_perform_relocation;
+ }
+ /* end mips specific stuff */
+
+ r = bfd_perform_relocation (input_bfd,
+ *parent,
+ (PTR) data,
+ input_section,
+ relocateable ? abfd : (bfd *) NULL,
+ &error_message);
+ skip_bfd_perform_relocation:
+
+ if (relocateable)
+ {
+ asection *os = input_section->output_section;
+
+ /* A partial link, so keep the relocs */
+ os->orelocation[os->reloc_count] = *parent;
+ os->reloc_count++;
+ }
+
+ if (r != bfd_reloc_ok)
+ {
+ switch (r)
+ {
+ case bfd_reloc_undefined:
+ if (!((*link_info->callbacks->undefined_symbol)
+ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ input_bfd, input_section, (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_dangerous:
+ BFD_ASSERT (error_message != (char *) NULL);
+ if (!((*link_info->callbacks->reloc_dangerous)
+ (link_info, error_message, input_bfd, input_section,
+ (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_overflow:
+ if (!((*link_info->callbacks->reloc_overflow)
+ (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
+ (*parent)->howto->name, (*parent)->addend,
+ input_bfd, input_section, (*parent)->address)))
+ goto error_return;
+ break;
+ case bfd_reloc_outofrange:
+ default:
+ abort ();
+ break;
+ }
+
+ }
+ }
+ }
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return data;
+
+error_return:
+ if (reloc_vector != NULL)
+ free (reloc_vector);
+ return NULL;
+}
+#define bfd_elf32_bfd_get_relocated_section_contents elf32_mips_get_relocated_section_contents
+\f
/* ECOFF swapping routines. These are used when dealing with the
.mdebug section, which is in the ECOFF debugging format. */
static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
mips_elf_final_write_processing
#define elf_backend_ecoff_debug_swap &mips_elf_ecoff_debug_swap
+#define bfd_elf32_bfd_is_local_label mips_elf_is_local_label
+#define bfd_elf32_find_nearest_line mips_elf_find_nearest_line
+
#define bfd_elf32_bfd_link_hash_table_create \
mips_elf_link_hash_table_create
#define bfd_elf32_bfd_final_link mips_elf_final_link