/* MIPS-specific support for ELF
- Copyright (C) 1993-2019 Free Software Foundation, Inc.
+ Copyright (C) 1993-2020 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
#include "libbfd.h"
#include "libiberty.h"
#include "elf-bfd.h"
+#include "ecoff-bfd.h"
#include "elfxx-mips.h"
#include "elf/mips.h"
#include "elf-vxworks.h"
/* The greatest dynamic symbol table index corresponding to an external
symbol without a GOT entry. */
bfd_size_type max_non_got_dynindx;
+ /* If non-NULL, output BFD for .MIPS.xhash finalization. */
+ bfd *output_bfd;
+ /* If non-NULL, pointer to contents of .MIPS.xhash for filling in
+ real final dynindx. */
+ bfd_byte *mipsxhash;
};
/* We make up to two PLT entries if needed, one for standard MIPS code
being called returns a floating point value. */
asection *call_fp_stub;
+ /* If non-zero, location in .MIPS.xhash to write real final dynindx. */
+ bfd_vma mipsxhash_loc;
+
/* The highest GGA_* value that satisfies all references to this symbol. */
unsigned int global_got_area : 2;
ret->fn_stub = NULL;
ret->call_stub = NULL;
ret->call_fp_stub = NULL;
+ ret->mipsxhash_loc = 0;
ret->global_got_area = GGA_NONE;
ret->got_only_for_calls = TRUE;
ret->readonly_reloc = FALSE;
{
const char *name;
- name = bfd_get_section_name (section->owner, section);
+ name = bfd_section_name (section);
return (FN_STUB_P (name)
|| CALL_STUB_P (name)
|| CALL_FP_STUB_P (name)
/* Make sure that any padding goes before the stub. */
align = input_section->alignment_power;
- if (!bfd_set_section_alignment (s->owner, s, align))
+ if (!bfd_set_section_alignment (s, align))
return FALSE;
if (align > 3)
s->size = (1 << align) - 8;
asection *input_section = stub->h->root.root.u.def.section;
s = htab->add_stub_section (".text", NULL,
input_section->output_section);
- if (s == NULL || !bfd_set_section_alignment (s->owner, s, 4))
+ if (s == NULL || !bfd_set_section_alignment (s, 4))
return FALSE;
htab->strampoline = s;
}
bfd *output_bfd, char **error_message)
{
if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
- || bfd_is_und_section (bfd_get_section (symbol))
- || bfd_is_com_section (bfd_get_section (symbol)))
+ || bfd_is_und_section (bfd_asymbol_section (symbol))
+ || bfd_is_com_section (bfd_asymbol_section (symbol)))
/* The relocation is against a global symbol. */
return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd,
h->esym.asym.sc = scUndefined;
else
{
- name = bfd_section_name (output_section->owner, output_section);
+ name = bfd_section_name (output_section);
if (strcmp (name, ".text") == 0)
h->esym.asym.sc = scText;
| SEC_LINKER_CREATED
| SEC_READONLY));
if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc,
- MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
+ || !bfd_set_section_alignment (sreloc,
+ MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
return NULL;
}
return sreloc;
at the head of the table; see `_bfd_elf_link_renumber_dynsyms'. */
hsd.max_local_dynindx = count_section_dynsyms (abfd, info) + 1;
hsd.max_non_got_dynindx = htab->root.local_dynsymcount + 1;
+ hsd.output_bfd = abfd;
+ if (htab->root.dynobj != NULL
+ && htab->root.dynamic_sections_created
+ && info->emit_gnu_hash)
+ {
+ asection *s = bfd_get_linker_section (htab->root.dynobj, ".MIPS.xhash");
+ BFD_ASSERT (s != NULL);
+ hsd.mipsxhash = s->contents;
+ BFD_ASSERT (hsd.mipsxhash != NULL);
+ }
+ else
+ hsd.mipsxhash = NULL;
mips_elf_link_hash_traverse (htab, mips_elf_sort_hash_table_f, &hsd);
/* There should have been enough room in the symbol table to
break;
}
+ /* Populate the .MIPS.xhash translation table entry with
+ the symbol dynindx. */
+ if (h->mipsxhash_loc != 0 && hsd->mipsxhash != NULL)
+ bfd_put_32 (hsd->output_bfd, h->root.dynindx,
+ hsd->mipsxhash + h->mipsxhash_loc);
+
return TRUE;
}
s = bfd_make_section_anyway_with_flags (abfd, ".compact_rel", flags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
return FALSE;
s->size = sizeof (Elf32_External_compact_rel);
in the function stub generation and in the linker script. */
s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s, 4))
+ || !bfd_set_section_alignment (s, 4))
return FALSE;
htab->root.sgot = s;
symtab_hdr->sh_link,
sym->st_name);
if (*namep == NULL || **namep == '\0')
- *namep = bfd_section_name (input_bfd, sec);
+ *namep = bfd_section_name (sec);
/* For relocations against a section symbol and ones against no
symbol (absolute relocations) infer the ISA mode from the addend. */
sec = NULL;
for (o = input_bfd->sections; o != NULL; o = o->next)
{
- if (CALL_FP_STUB_P (bfd_get_section_name (input_bfd, o)))
+ if (CALL_FP_STUB_P (bfd_section_name (o)))
{
sec = h->call_fp_stub;
break;
}
/* Make this the JALX opcode. */
- x = (x & ~(0x3f << 26)) | (jalx_opcode << 26);
+ x = (x & ~(0x3fu << 26)) | (jalx_opcode << 26);
}
else if (cross_mode_jump_p && b_reloc_p (r_type))
{
if (hdr->bfd_section != NULL)
{
- const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
+ const char *name = bfd_section_name (hdr->bfd_section);
/* .sbss is not handled specially here because the GNU/Linux
prelinker can convert .sbss from NOBITS to PROGBITS and
&& ! CONST_STRNEQ (name, ".MIPS.post_rel"))
return FALSE;
break;
+ case SHT_MIPS_XHASH:
+ if (strcmp (name, ".MIPS.xhash") != 0)
+ return FALSE;
default:
break;
}
if (flags)
{
- if (! bfd_set_section_flags (abfd, hdr->bfd_section,
- (bfd_get_section_flags (abfd,
- hdr->bfd_section)
- | flags)))
+ if (!bfd_set_section_flags (hdr->bfd_section,
+ (bfd_section_flags (hdr->bfd_section)
+ | flags)))
return FALSE;
}
bfd_boolean
_bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
{
- const char *name = bfd_get_section_name (abfd, sec);
+ const char *name = bfd_section_name (sec);
if (strcmp (name, ".liblist") == 0)
{
hdr->sh_flags |= SHF_ALLOC;
hdr->sh_entsize = 8;
}
+ else if (strcmp (name, ".MIPS.xhash") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_XHASH;
+ hdr->sh_flags |= SHF_ALLOC;
+ hdr->sh_entsize = get_elf_backend_data(abfd)->s->arch_size == 64 ? 0 : 4;
+ }
/* The generic elf_fake_sections will set up REL_HDR using the default
kind of relocations. We used to set up a second header for the
_bfd_mips_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED,
asection *sec, int *retval)
{
- if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0)
+ if (strcmp (bfd_section_name (sec), ".scommon") == 0)
{
*retval = SHN_MIPS_SCOMMON;
return TRUE;
}
- if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0)
+ if (strcmp (bfd_section_name (sec), ".acommon") == 0)
{
*retval = SHN_MIPS_ACOMMON;
return TRUE;
s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
{
- if (! bfd_set_section_flags (abfd, s, flags))
+ if (!bfd_set_section_flags (s, flags))
return FALSE;
}
}
MIPS_ELF_STUB_SECTION_NAME (abfd),
flags | SEC_CODE);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
return FALSE;
htab->sstubs = s;
s = bfd_make_section_anyway_with_flags (abfd, ".rld_map",
flags &~ (flagword) SEC_READONLY);
if (s == NULL
- || ! bfd_set_section_alignment (abfd, s,
- MIPS_ELF_LOG_FILE_ALIGN (abfd)))
+ || !bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd)))
return FALSE;
}
+ /* Create .MIPS.xhash section. */
+ if (info->emit_gnu_hash)
+ s = bfd_make_section_anyway_with_flags (abfd, ".MIPS.xhash",
+ flags | SEC_READONLY);
+
/* On IRIX5, we adjust add some additional symbols and change the
alignments of several sections. There is no ABI documentation
indicating that this is necessary on IRIX6, nor any evidence that
/* Change alignments of some sections. */
s = bfd_get_linker_section (abfd, ".hash");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynsym");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynstr");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
/* ??? */
s = bfd_get_section_by_name (abfd, ".reginfo");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
s = bfd_get_linker_section (abfd, ".dynamic");
if (s != NULL)
- (void) bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
+ bfd_set_section_alignment (s, MIPS_ELF_LOG_FILE_ALIGN (abfd));
}
if (bfd_link_executable (info))
/* Check for the mips16 stub sections. */
- name = bfd_get_section_name (abfd, sec);
+ name = bfd_section_name (sec);
if (FN_STUB_P (name))
{
unsigned long r_symndx;
Encourage better cache usage by aligning. We do this
lazily to avoid pessimizing traditional objects. */
if (!htab->is_vxworks
- && !bfd_set_section_alignment (dynobj, htab->root.splt, 5))
+ && !bfd_set_section_alignment (htab->root.splt, 5))
return FALSE;
/* Make sure that .got.plt is word-aligned. We do this lazily
for the same reason as above. */
- if (!bfd_set_section_alignment (dynobj, htab->root.sgotplt,
+ if (!bfd_set_section_alignment (htab->root.sgotplt,
MIPS_ELF_LOG_FILE_ALIGN (dynobj)))
return FALSE;
sect = bfd_get_section_by_name (output_bfd, ".reginfo");
if (sect != NULL)
{
- bfd_set_section_size (output_bfd, sect, sizeof (Elf32_External_RegInfo));
+ bfd_set_section_size (sect, sizeof (Elf32_External_RegInfo));
sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
}
sect = bfd_get_section_by_name (output_bfd, ".MIPS.abiflags");
if (sect != NULL)
{
- bfd_set_section_size (output_bfd, sect,
- sizeof (Elf_External_ABIFlags_v0));
+ bfd_set_section_size (sect, sizeof (Elf_External_ABIFlags_v0));
sect->flags |= SEC_FIXED_SIZE | SEC_HAS_CONTENTS;
}
/* It's OK to base decisions on the section name, because none
of the dynobj section names depend upon the input files. */
- name = bfd_get_section_name (dynobj, s);
+ name = bfd_section_name (s);
if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
assert a DT_TEXTREL entry rather than testing whether
there exists a relocation to a read only section or
not. */
- outname = bfd_get_section_name (output_bfd,
- s->output_section);
+ outname = bfd_section_name (s->output_section);
target = bfd_get_section_by_name (output_bfd, outname + 4);
if ((target != NULL
&& (target->flags & SEC_READONLY) != 0
if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0))
return FALSE;
+ if (info->emit_gnu_hash
+ && ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_XHASH, 0))
+ return FALSE;
+
if (IRIX_COMPAT (dynobj) == ict_irix5
&& ! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_HIPAGENO, 0))
return FALSE;
swap_out_p = FALSE;
break;
+ case DT_MIPS_XHASH:
+ name = ".MIPS.xhash";
+ s = bfd_get_linker_section (dynobj, name);
+ dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
+ break;
+
default:
swap_out_p = FALSE;
if (htab->is_vxworks
switch (bfd_get_mach (abfd))
{
default:
+ if (ABI_N32_P (abfd) || ABI_64_P (abfd))
+ val = E_MIPS_ARCH_3;
+ else
+ val = E_MIPS_ARCH_1;
+ break;
+
case bfd_mach_mips3000:
val = E_MIPS_ARCH_1;
break;
number. This is used by both the 32-bit and the 64-bit ABI. */
void
-_bfd_mips_elf_final_write_processing (bfd *abfd,
- bfd_boolean linker ATTRIBUTE_UNUSED)
+_bfd_mips_final_write_processing (bfd *abfd)
{
unsigned int i;
Elf_Internal_Shdr **hdrpp;
case SHT_MIPS_GPTAB:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL
&& CONST_STRNEQ (name, ".gptab."));
sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
case SHT_MIPS_CONTENT:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL
&& CONST_STRNEQ (name, ".MIPS.content"));
sec = bfd_get_section_by_name (abfd,
case SHT_MIPS_EVENTS:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
- name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ name = bfd_section_name ((*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL);
if (CONST_STRNEQ (name, ".MIPS.events"))
sec = bfd_get_section_by_name (abfd,
(*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
break;
+ case SHT_MIPS_XHASH:
+ sec = bfd_get_section_by_name (abfd, ".dynsym");
+ if (sec != NULL)
+ (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
}
}
}
+
+bfd_boolean
+_bfd_mips_elf_final_write_processing (bfd *abfd)
+{
+ _bfd_mips_final_write_processing (abfd);
+ return _bfd_elf_final_write_processing (abfd);
+}
\f
/* When creating an IRIX5 executable, we need REGINFO and RTPROC
segments. */
for (o = sub->sections; o != NULL; o = o->next)
if (!o->gc_mark
- && MIPS_ELF_ABIFLAGS_SECTION_NAME_P
- (bfd_get_section_name (sub, o)))
+ && MIPS_ELF_ABIFLAGS_SECTION_NAME_P (bfd_section_name (o)))
{
if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
return FALSE;
filename_ptr, functionname_ptr,
line_ptr, discriminator_ptr,
dwarf_debug_sections,
- ABI_64_P (abfd) ? 8 : 0,
&elf_tdata (abfd)->dwarf2_find_line_info)
- || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr,
- line_ptr))
- {
- /* PR 22789: If the function name or filename was not found through
- the debug information, then try an ordinary lookup instead. */
- if ((functionname_ptr != NULL && *functionname_ptr == NULL)
- || (filename_ptr != NULL && *filename_ptr == NULL))
- {
- /* Do not override already discovered names. */
- if (functionname_ptr != NULL && *functionname_ptr != NULL)
- functionname_ptr = NULL;
-
- if (filename_ptr != NULL && *filename_ptr != NULL)
- filename_ptr = NULL;
-
- _bfd_elf_find_function (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr);
- }
+ == 1)
+ return TRUE;
+ if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ {
+ if (!*functionname_ptr)
+ _bfd_elf_find_function (abfd, symbols, section, offset,
+ *filename_ptr ? NULL : filename_ptr,
+ functionname_ptr);
return TRUE;
}
".rtproc",
flags);
if (rtproc_sec == NULL
- || ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
+ || !bfd_set_section_alignment (rtproc_sec, 4))
return FALSE;
}
return "DT_MIPS_PLTGOT";
case DT_MIPS_RWPLT:
return "DT_MIPS_RWPLT";
+ case DT_MIPS_XHASH:
+ return "DT_MIPS_XHASH";
}
}
{ STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL },
{ STRING_COMMA_LEN (".ucode"), 0, SHT_MIPS_UCODE, 0 },
+ { STRING_COMMA_LEN (".MIPS.xhash"), 0, SHT_MIPS_XHASH, SHF_ALLOC },
{ NULL, 0, 0, 0, 0 }
};
MIPS_LIBC_ABI_UNIQUE,
MIPS_LIBC_ABI_MIPS_O32_FP64,
MIPS_LIBC_ABI_ABSOLUTE,
+ MIPS_LIBC_ABI_XHASH,
MIPS_LIBC_ABI_MAX
};
-void
-_bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
+bfd_boolean
+_bfd_mips_init_file_header (bfd *abfd, struct bfd_link_info *link_info)
{
struct mips_elf_link_hash_table *htab = NULL;
Elf_Internal_Ehdr *i_ehdrp;
+ if (!_bfd_elf_init_file_header (abfd, link_info))
+ return FALSE;
+
i_ehdrp = elf_elfheader (abfd);
if (link_info)
{
if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
- _bfd_elf_post_process_headers (abfd, link_info);
+ /* Mark that we need support for .MIPS.xhash in the dynamic linker,
+ if it is the only hash section that will be created. */
+ if (link_info && link_info->emit_gnu_hash && !link_info->emit_hash)
+ i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_XHASH;
+ return TRUE;
}
int
{
return COMPACT_EH_CANT_UNWIND_OPCODE;
}
+
+/* Record a position XLAT_LOC in the xlat translation table, associated with
+ the hash entry H. The entry in the translation table will later be
+ populated with the real symbol dynindx. */
+
+void
+_bfd_mips_elf_record_xhash_symbol (struct elf_link_hash_entry *h,
+ bfd_vma xlat_loc)
+{
+ struct mips_elf_link_hash_entry *hmips;
+
+ hmips = (struct mips_elf_link_hash_entry *) h;
+ hmips->mipsxhash_loc = xlat_loc;
+}