/* MIPS-specific support for 32-bit ELF
- Copyright 1993, 94, 95, 96, 97, 98, 99, 2000
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
/* This structure is used to hold .got information when linking. It
is stored in the tdata field of the bfd_elf_section_data structure. */
-struct mips_got_info {
+struct mips_got_info
+{
/* The global symbol in the GOT with the lowest index in the dynamic
symbol table. */
struct elf_link_hash_entry *global_gotsym;
/* The MIPS ELF linker needs additional information for each symbol in
the global hash table. */
-struct mips_elf_link_hash_entry {
+struct mips_elf_link_hash_entry
+{
struct elf_link_hash_entry root;
/* External symbol information. */
section) against this symbol. */
unsigned int min_dyn_reloc_index;
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address, i.e. any but
+ R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+ p. 4-20. */
+ boolean no_fn_stub;
+
/* If there is a stub that 32 bit functions should use to call this
16 bit function, this points to the section containing the stub. */
asection *fn_stub;
static boolean mips_elf_create_dynamic_relocation
PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
struct mips_elf_link_hash_entry *, asection *,
- bfd_vma, bfd_vma *, asection *, boolean local_p));
+ bfd_vma, bfd_vma *, asection *));
static void mips_elf_allocate_dynamic_relocations
PARAMS ((bfd *, unsigned int));
static boolean mips_elf_stub_section_p
PARAMS ((const void *, const void *));
extern const bfd_target bfd_elf32_tradbigmips_vec;
+extern const bfd_target bfd_elf32_tradlittlemips_vec;
+extern const bfd_target bfd_elf64_tradbigmips_vec;
+extern const bfd_target bfd_elf64_tradlittlemips_vec;
/* The level of IRIX compatibility we're striving for. */
#define ABI_N32_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
-/* Nonzero if ABFD is using the 64-bit ABI. FIXME: This is never
- true, yet. */
+/* Nonzero if ABFD is using the 64-bit ABI. */
#define ABI_64_P(abfd) \
((elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) != 0)
executables or "normal" MIPS ELF ABI executables. */
#define IRIX_COMPAT(abfd) \
- (abfd->xvec == &bfd_elf32_tradbigmips_vec ? ict_none : \
+ (((abfd->xvec == &bfd_elf64_tradbigmips_vec) || \
+ (abfd->xvec == &bfd_elf64_tradlittlemips_vec) || \
+ (abfd->xvec == &bfd_elf32_tradbigmips_vec) || \
+ (abfd->xvec == &bfd_elf32_tradlittlemips_vec)) ? ict_none : \
((ABI_N32_P (abfd) || ABI_64_P (abfd)) ? ict_irix6 : ict_irix5))
/* Whether we are trying to be compatible with IRIX at all. */
/* Names of sections which appear in the .dynsym section in an Irix 5
executable. */
-static const char * const mips_elf_dynsym_sec_names[] = {
+static const char * const mips_elf_dynsym_sec_names[] =
+{
".text",
".init",
".fini",
/* The names of the runtime procedure table symbols used on Irix 5. */
-static const char * const mips_elf_dynsym_rtproc_names[] = {
+static const char * const mips_elf_dynsym_rtproc_names[] =
+{
"_procedure_table",
"_procedure_string_table",
"_procedure_table_size",
/* These structures are used to generate the .compact_rel section on
Irix 5. */
-typedef struct {
+typedef struct
+{
unsigned long id1; /* Always one? */
unsigned long num; /* Number of compact relocation entries. */
unsigned long id2; /* Always two? */
unsigned long reserved1; /* Zero? */
} Elf32_compact_rel;
-typedef struct {
+typedef struct
+{
bfd_byte id1[4];
bfd_byte num[4];
bfd_byte id2[4];
bfd_byte reserved1[4];
} Elf32_External_compact_rel;
-typedef struct {
+typedef struct
+{
unsigned int ctype : 1; /* 1: long 0: short format. See below. */
unsigned int rtype : 4; /* Relocation types. See below. */
unsigned int dist2to : 8;
unsigned long vaddr; /* VADDR to be relocated. */
} Elf32_crinfo;
-typedef struct {
+typedef struct
+{
unsigned int ctype : 1; /* 1: long 0: short format. See below. */
unsigned int rtype : 4; /* Relocation types. See below. */
unsigned int dist2to : 8;
unsigned long konst; /* KONST field. See below. */
} Elf32_crinfo2;
-typedef struct {
+typedef struct
+{
bfd_byte info[4];
bfd_byte konst[4];
bfd_byte vaddr[4];
} Elf32_External_crinfo;
-typedef struct {
+typedef struct
+{
bfd_byte info[4];
bfd_byte konst[4];
} Elf32_External_crinfo2;
from smaller values. Start with zero, widen, *then* decrement. */
#define MINUS_ONE (((bfd_vma)0) - 1)
-static reloc_howto_type elf_mips_howto_table[] = {
+static reloc_howto_type elf_mips_howto_table[] =
+{
/* No relocation. */
HOWTO (R_MIPS_NONE, /* type */
0, /* rightshift */
complain_overflow_dont, /* complain_on_overflow */
/* This needs complex overflow
detection, because the upper four
- bits must match the PC. */
+ bits must match the PC + 4. */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_26", /* name */
true, /* partial_inplace */
reloc. This extension permits gcc to output the HI and LO relocs
itself. */
-struct mips_hi16 {
+struct mips_hi16
+{
struct mips_hi16 *next;
bfd_byte *addr;
bfd_vma addend;
return 3;
case E_MIPS_ARCH_4:
return 4;
+ case E_MIPS_ARCH_5:
+ return 5;
case E_MIPS_ARCH_32:
return 32;
+ case E_MIPS_ARCH_64:
+ return 64;
}
return 4;
}
case E_MIPS_MACH_MIPS32_4K:
return bfd_mach_mips32_4k;
+ case E_MIPS_MACH_SB1:
+ return bfd_mach_mips_sb1;
+
default:
switch (flags & EF_MIPS_ARCH)
{
return bfd_mach_mips8000;
break;
+ case E_MIPS_ARCH_5:
+ return bfd_mach_mips5;
+ break;
+
case E_MIPS_ARCH_32:
return bfd_mach_mips32;
break;
+
+ case E_MIPS_ARCH_64:
+ return bfd_mach_mips64;
+ break;
}
}
enum elf_mips_reloc_type elf_reloc_val;
};
-static CONST struct elf_reloc_map mips_reloc_map[] = {
+static CONST struct elf_reloc_map mips_reloc_map[] =
+{
{ BFD_RELOC_NONE, R_MIPS_NONE, },
{ BFD_RELOC_16, R_MIPS_16 },
{ BFD_RELOC_32, R_MIPS_32 },
bfd *abfd ATTRIBUTE_UNUSED;
asymbol *sym;
{
- return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
+ if (SGI_COMPAT(abfd))
+ return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
+ else
+ return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
+ || bfd_is_und_section (bfd_get_section (sym))
+ || bfd_is_com_section (bfd_get_section (sym)));
}
\f
/* Set the right machine number for a MIPS ELF file. This is used for
case bfd_mach_mips32_4k:
val = E_MIPS_ARCH_32 | E_MIPS_MACH_MIPS32_4K;
break;
+
+ case bfd_mach_mips5:
+ val = E_MIPS_ARCH_5;
+ break;
+
+ case bfd_mach_mips64:
+ val = E_MIPS_ARCH_64;
+ break;
+
+ case bfd_mach_mips_sb1:
+ val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1;
+ break;
}
elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH);
flagword old_flags;
flagword new_flags;
boolean ok;
+ boolean null_input_bfd = true;
+ asection *sec;
/* Check if we have the same endianess */
if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
if (new_flags == old_flags)
return true;
+ /* Check to see if the input BFD actually contains any sections.
+ If not, its flags may not have been initialised either, but it cannot
+ actually cause any incompatibility. */
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ {
+ /* Ignore synthetic sections and empty .text, .data and .bss sections
+ which are automatically generated by gas. */
+ if (strcmp (sec->name, ".reginfo")
+ && strcmp (sec->name, ".mdebug")
+ && ((!strcmp (sec->name, ".text")
+ || !strcmp (sec->name, ".data")
+ || !strcmp (sec->name, ".bss"))
+ && sec->_raw_size != 0))
+ {
+ null_input_bfd = false;
+ break;
+ }
+ }
+ if (null_input_bfd)
+ return true;
+
ok = true;
if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC))
fprintf (file, _(" [mips3]"));
else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4)
fprintf (file, _(" [mips4]"));
+ else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_5)
+ fprintf (file, _ (" [mips5]"));
else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32)
fprintf (file, _ (" [mips32]"));
+ else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64)
+ fprintf (file, _ (" [mips64]"));
else
fprintf (file, _(" [unknown ISA]"));
if (m != NULL
&& m->count == 1 && strcmp (m->sections[0]->name, ".dynamic") == 0)
{
- static const char *sec_names[] = {
+ static const char *sec_names[] =
+ {
".dynamic", ".dynstr", ".dynsym", ".hash"
};
bfd_vma low, high;
/* MIPS ELF uses a special find_nearest_line routine in order the
handle the ECOFF debugging information. */
-struct mips_elf_find_line {
+struct mips_elf_find_line
+{
struct ecoff_debug_info d;
struct ecoff_find_line i;
};
if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
filename_ptr, functionname_ptr,
line_ptr,
- ABI_64_P (abfd) ? 8 : 0))
+ ABI_64_P (abfd) ? 8 : 0,
+ &elf_tdata (abfd)->dwarf2_find_line_info))
return true;
msec = bfd_get_section_by_name (abfd, ".mdebug");
/* MIPS ELF linker hash table. */
-struct mips_elf_link_hash_table {
+struct mips_elf_link_hash_table
+{
struct elf_link_hash_table root;
#if 0
/* We no longer use this. */
ret->esym.ifd = -2;
ret->possibly_dynamic_relocs = 0;
ret->min_dyn_reloc_index = 0;
+ ret->no_fn_stub = false;
ret->fn_stub = NULL;
ret->need_fn_stub = false;
ret->call_stub = NULL;
/* Structure used to pass information to mips_elf_output_extsym. */
-struct extsym_info {
+struct extsym_info
+{
bfd *abfd;
struct bfd_link_info *info;
struct ecoff_debug_info *debug;
}
else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
- /* Set type and value for a symbol with a function stub. */
- h->esym.asym.st = stProc;
- sec = h->root.root.u.def.section;
- if (sec == NULL)
- h->esym.asym.value = 0;
- else
+ struct mips_elf_link_hash_entry *hd = h;
+ boolean no_fn_stub = h->no_fn_stub;
+
+ while (hd->root.root.type == bfd_link_hash_indirect)
{
- output_section = sec->output_section;
- if (output_section != NULL)
- h->esym.asym.value = (h->root.plt.offset
- + sec->output_offset
- + output_section->vma);
- else
- h->esym.asym.value = 0;
+ hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link;
+ no_fn_stub = no_fn_stub || hd->no_fn_stub;
}
+
+ if (!no_fn_stub)
+ {
+ /* Set type and value for a symbol with a function stub. */
+ h->esym.asym.st = stProc;
+ sec = hd->root.root.u.def.section;
+ if (sec == NULL)
+ h->esym.asym.value = 0;
+ else
+ {
+ output_section = sec->output_section;
+ if (output_section != NULL)
+ h->esym.asym.value = (hd->root.plt.offset
+ + sec->output_offset
+ + output_section->vma);
+ else
+ h->esym.asym.value = 0;
+ }
#if 0 /* FIXME? */
- h->esym.ifd = 0;
+ h->esym.ifd = 0;
#endif
+ }
}
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
EXTR esym;
bfd_vma last;
unsigned int i;
- static const char * const name[] = {
+ static const char * const name[] =
+ {
".text", ".init", ".fini", ".data",
".rodata", ".sdata", ".sbss", ".bss"
};
- static const int sc[] = {
+ static const int sc[] =
+ {
scText, scInit, scFini, scData,
scRData, scSData, scSBss, scBss
};
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
the dynamic symbols. */
-struct mips_elf_hash_sort_data {
+struct mips_elf_hash_sort_data
+{
/* The symbol in the global GOT with the lowest dynamic symbol table
index. */
struct elf_link_hash_entry *low;
static boolean
mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec,
- symbol, addendp, input_section, local_p)
+ symbol, addendp, input_section)
bfd *output_bfd;
struct bfd_link_info *info;
const Elf_Internal_Rela *rel;
bfd_vma symbol;
bfd_vma *addendp;
asection *input_section;
- boolean local_p;
{
Elf_Internal_Rel outrel;
boolean skip;
/* The relocation we're building is section-relative.
Therefore, the original addend must be adjusted by the
section offset. */
- *addendp += symbol - sec->output_section->vma;
+ *addendp += section_offset;
/* Now, the relocation is just against the section. */
symbol = sec->output_section->vma;
}
- /* If the relocation is against a local symbol was previously an
- absolute relocation, we must adjust it by the value we give
- it in the dynamic symbol table. */
- if (local_p && r_type != R_MIPS_REL32)
+ /* If the relocation was previously an absolute relocation and
+ this symbol will not be referred to by the relocation, we must
+ adjust it by the value we give it in the dynamic symbol table.
+ Otherwise leave the job up to the dynamic linker. */
+ if (!indx && r_type != R_MIPS_REL32)
*addendp += symbol;
/* The relocation is always an REL32 relocation because we don't
symbol + addend, sgot->contents + g);
}
}
- else if (r_type == R_MIPS_GOT16)
+ else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
/* There's no need to create a local GOT entry here; the
calculation for a local GOT16 entry does not involve G. */
break;
sec,
symbol,
&value,
- input_section, local_p))
+ input_section))
return false;
}
else
break;
case R_MIPS16_26:
- /* The calculation for R_MIPS_26 is just the same as for an
+ /* The calculation for R_MIPS16_26 is just the same as for an
R_MIPS_26. It's only the storage of the relocated field into
the output file that's different. That's handled in
mips_elf_perform_relocation. So, we just fall through to the
R_MIPS_26 case here. */
case R_MIPS_26:
if (local_p)
- value = (((addend << 2) | (p & 0xf0000000)) + symbol) >> 2;
+ value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2;
else
value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2;
value &= howto->dst_mask;
break;
case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
if (local_p)
{
boolean forced;
/* Fall through. */
- case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
((sub1 << 16) | sub2)).
When producing a relocateable object file, the calculation is
- (((A < 2) | (P & 0xf0000000) + S) >> 2)
+ (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
When producing a fully linked file, the calculation is
- let R = (((A < 2) | (P & 0xf0000000) + S) >> 2)
+ let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) */
if (!info->relocateable)
value = (((value & 0x1f0000) << 5)
| ((value & 0x3e00000) >> 5)
| (value & 0xffff));
-
}
else if (r_type == R_MIPS16_GPREL)
{
REL relocation. */
boolean rela_relocation_p = true;
int r_type = ELF32_R_TYPE (rel->r_info);
+ const char * msg = (const char *) NULL;
/* Find the relocation howto for this relocation. */
if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd))
continue;
case bfd_reloc_notsupported:
- abort ();
- break;
+ msg = _("internal error: unsupported relocation error");
+ info->callbacks->warning
+ (info, msg, name, input_bfd, input_section, rel->r_offset);
+ return false;
case bfd_reloc_overflow:
if (use_saved_addend_p)
/* We may need a local GOT entry for this relocation. We
don't count R_MIPS_GOT_PAGE because we can estimate the
maximum number of pages needed by looking at the size of
- the segment. Similar comments apply to R_MIPS_GOT16. We
- don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because
- these are always followed by an R_MIPS_GOT_LO16 or
- R_MIPS_CALL_LO16.
+ the segment. Similar comments apply to R_MIPS_GOT16 and
+ R_MIPS_CALL16. We don't count R_MIPS_GOT_HI16, or
+ R_MIPS_CALL_HI16 because these are always followed by an
+ R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
This estimation is very conservative since we can merge
duplicate entries in the GOT. In order to be less
break;
}
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address. */
+ switch (r_type)
+ {
+ default:
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *mh;
+
+ mh = (struct mips_elf_link_hash_entry *) h;
+ mh->no_fn_stub = true;
+ }
+ break;
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ break;
+ }
+
/* If this reloc is not a 16 bit call, and it has a global
symbol, then we will need the fn_stub if there is one.
References from a stub section do not count. */
|| (indmips->min_dyn_reloc_index != 0
&& indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+ if (indmips->no_fn_stub)
+ dirmips->no_fn_stub = true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
mips_elf_allocate_dynamic_relocations (dynobj,
hmips->possibly_dynamic_relocs);
- /* For a function, create a stub, if needed. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ /* For a function, create a stub, if allowed. */
+ if (! hmips->no_fn_stub
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
if (! elf_hash_table (info)->dynamic_sections_created)
return true;