aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog46
-rw-r--r--bfd/elf-bfd.h7
-rw-r--r--bfd/elflink.c46
-rw-r--r--bfd/elfxx-mips.c78
-rw-r--r--bfd/elfxx-mips.h4
-rw-r--r--bfd/elfxx-target.h5
-rw-r--r--binutils/ChangeLog10
-rw-r--r--binutils/readelf.c52
-rw-r--r--include/ChangeLog5
-rw-r--r--include/elf/mips.h6
-rw-r--r--ld/ChangeLog16
-rw-r--r--ld/emulparams/elf32bmip.sh1
-rw-r--r--ld/emulparams/elf32bmipn32-defs.sh1
-rw-r--r--ld/emulparams/elf64bmip-defs.sh1
-rw-r--r--ld/emultempl/mipself.em16
-rw-r--r--ld/testsuite/ld-elf/hash.d2
-rw-r--r--ld/testsuite/ld-mips-elf/hash1.d11
-rw-r--r--ld/testsuite/ld-mips-elf/hash1.s8
-rw-r--r--ld/testsuite/ld-mips-elf/hash1a.d5
-rw-r--r--ld/testsuite/ld-mips-elf/hash1b.d4
-rw-r--r--ld/testsuite/ld-mips-elf/hash1c.d4
-rw-r--r--ld/testsuite/ld-mips-elf/hash2.d17
-rw-r--r--ld/testsuite/ld-mips-elf/mips-elf.exp5
-rw-r--r--ld/testsuite/ld-mips-elf/start.s12
24 files changed, 314 insertions, 48 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 7b0da65..cf2fec7 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,49 @@
+2019-08-09 Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
+
+ * elf-bfd.h (struct elf_backend_data): New members.
+ * elflink.c (_bfd_elf_link_create_dynamic_sections): Create
+ .gnu.hash section if necessary.
+ (struct collect_gnu_hash_codes): New member.
+ (elf_gnu_hash_process_symidx): New function name.
+ (elf_renumber_gnu_hash_syms): Ignore local and undefined
+ symbols. Record xlat location for every symbol which should have
+ a .MIPS.xhash entry.
+ (bfd_elf_size_dynamic_sections): Add DT_GNU_HASH dynamic tag to
+ dynamic section if necessary.
+ (GNU_HASH_SECTION_NAME): New define.
+ (bfd_elf_size_dynsym_hash_dynstr): Get .MIPS.xhash section.
+ Update the section size info.
+ * elfxx-mips.c (struct mips_elf_hash_sort_data): New members.
+ (struct mips_elf_link_hash_entry): New member.
+ (mips_elf_link_hash_newfunc): Initialize .MIPS.xhash translation
+ table location.
+ (mips_elf_sort_hash_table): Initialize the pointer to the
+ .MIPS.xhash section.
+ (mips_elf_sort_hash_table_f): Populate the .MIPS.xhash
+ translation table entry with the symbol dynindx.
+ (_bfd_mips_elf_section_from_shdr): Add SHT_MIPS_XHASH.
+ (_bfd_mips_elf_fake_sections): Initialize .MIPS.xhash section
+ info.
+ (_bfd_mips_elf_create_dynamic_sections): Create .MIPS.xhash
+ section.
+ (_bfd_mips_elf_size_dynamic_sections): Add DT_MIPS_XHASH tag to
+ dynamic section.
+ (_bfd_mips_elf_finish_synamic_sections): Add DT_MIPS_XHASH.
+ (_bfd_mips_elf_final_write_processing): Set .MIPS.xhash section
+ sh_link info.
+ (_bfd_mips_elf_get_target_dtag): Get DT_MIPS_XHASH tag.
+ (MIPS_LIBC_ABI_XHASH): New ABI version enum value.
+ (_bfd_mips_post_process_headers): Mark the ABI version as
+ MIPS_LIBC_ABI_XHASH if there exists a .MIPS.xhash section,
+ but not a .hash section.
+ (_bfd_mips_elf_record_xhash_symbol): New function. Record a
+ position in the translation table, associated with the hash
+ entry.
+ * elfxx-mips.h (literal_reloc_p): Define
+ elf_backend_record_xhash_symbol backend hook.
+ * elfxx-target.h: Initialize elf_backend_record_xhash_symbol
+ backend hook.
+
2019-08-07 Jose E. Marchesi <jose.marchesi@oracle.com>
* elf64-bpf.c (bpf_elf_relocate_section): New function.
diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 225a8e5..521d35d 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -1392,6 +1392,13 @@ struct elf_backend_data
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *);
+ /* If non-NULL, called to register the location of XLAT_LOC within
+ .MIPS.xhash at which real final dynindx for H will be written.
+ If XLAT_LOC is zero, the symbol is not included in
+ .MIPS.xhash and no dynindx will be written. */
+ void (*record_xhash_symbol)
+ (struct elf_link_hash_entry *h, bfd_vma xlat_loc);
+
/* Return TRUE if type is a function symbol type. */
bfd_boolean (*is_function_type) (unsigned int type);
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 5971845..c7440d1 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -339,7 +339,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
}
- if (info->emit_gnu_hash)
+ if (info->emit_gnu_hash && bed->record_xhash_symbol == NULL)
{
s = bfd_make_section_anyway_with_flags (abfd, ".gnu.hash",
flags | SEC_READONLY);
@@ -5853,6 +5853,7 @@ struct collect_gnu_hash_codes
unsigned long int *counts;
bfd_vma *bitmask;
bfd_byte *contents;
+ bfd_size_type xlat;
long int min_dynindx;
unsigned long int bucketcount;
unsigned long int symindx;
@@ -5917,10 +5918,12 @@ elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data)
}
/* This function will be called though elf_link_hash_traverse to do
- final dynaminc symbol renumbering. */
+ final dynamic symbol renumbering in case of .gnu.hash.
+ If using .MIPS.xhash, invoke record_xhash_symbol to add symbol index
+ to the translation table. */
static bfd_boolean
-elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
+elf_gnu_hash_process_symidx (struct elf_link_hash_entry *h, void *data)
{
struct collect_gnu_hash_codes *s = (struct collect_gnu_hash_codes *) data;
unsigned long int bucket;
@@ -5934,7 +5937,15 @@ elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
if (! (*s->bed->elf_hash_symbol) (h))
{
if (h->dynindx >= s->min_dynindx)
- h->dynindx = s->local_indx++;
+ {
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ (*s->bed->record_xhash_symbol) (h, 0);
+ s->local_indx++;
+ }
+ else
+ h->dynindx = s->local_indx++;
+ }
return TRUE;
}
@@ -5951,7 +5962,14 @@ elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data)
bfd_put_32 (s->output_bfd, val,
s->contents + (s->indx[bucket] - s->symindx) * 4);
--s->counts[bucket];
- h->dynindx = s->indx[bucket]++;
+ if (s->bed->record_xhash_symbol != NULL)
+ {
+ bfd_vma xlat_loc = s->xlat + (s->indx[bucket]++ - s->symindx) * 4;
+
+ (*s->bed->record_xhash_symbol) (h, xlat_loc);
+ }
+ else
+ h->dynindx = s->indx[bucket]++;
return TRUE;
}
@@ -6980,7 +6998,8 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
if ((info->emit_hash
&& !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0))
|| (info->emit_gnu_hash
- && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0))
+ && (bed->record_xhash_symbol == NULL
+ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)))
|| !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0)
|| !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize)
@@ -7105,6 +7124,9 @@ _bfd_elf_init_2_index_sections (bfd *output_bfd, struct bfd_link_info *info)
elf_hash_table (info)->text_index_section = found;
}
+#define GNU_HASH_SECTION_NAME(bed) \
+ (bed)->record_xhash_symbol != NULL ? ".MIPS.xhash" : ".gnu.hash"
+
bfd_boolean
bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
{
@@ -7271,12 +7293,12 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
return FALSE;
}
- s = bfd_get_linker_section (dynobj, ".gnu.hash");
+ s = bfd_get_linker_section (dynobj, GNU_HASH_SECTION_NAME (bed));
BFD_ASSERT (s != NULL);
if (cinfo.nsyms == 0)
{
- /* Empty .gnu.hash section is special. */
+ /* Empty .gnu.hash or .MIPS.xhash section is special. */
BFD_ASSERT (cinfo.min_dynindx == -1);
free (cinfo.hashcodes);
s->size = 5 * 4 + bed->s->arch_size / 8;
@@ -7356,6 +7378,8 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
s->size = (4 + bucketcount + cinfo.nsyms) * 4;
s->size += cinfo.maskbits / 8;
+ if (bed->record_xhash_symbol != NULL)
+ s->size += cinfo.nsyms * 4;
contents = (unsigned char *) bfd_zalloc (output_bfd, s->size);
if (contents == NULL)
{
@@ -7382,9 +7406,11 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
cinfo.contents = contents;
- /* Renumber dynamic symbols, populate .gnu.hash section. */
+ cinfo.xlat = contents + cinfo.nsyms * 4 - s->contents;
+ /* Renumber dynamic symbols, if populating .gnu.hash section.
+ If using .MIPS.xhash, populate the translation table. */
elf_link_hash_traverse (elf_hash_table (info),
- elf_renumber_gnu_hash_syms, &cinfo);
+ elf_gnu_hash_process_symidx, &cinfo);
contents = s->contents + 16;
for (i = 0; i < maskwords; ++i)
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index 8e577b2..e845c90 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -322,6 +322,11 @@ struct mips_elf_hash_sort_data
/* 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
@@ -379,6 +384,9 @@ struct mips_elf_link_hash_entry
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;
@@ -1335,6 +1343,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
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;
@@ -3907,6 +3916,18 @@ mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
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
@@ -3958,6 +3979,12 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data)
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;
}
@@ -7475,6 +7502,9 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd,
&& ! CONST_STRNEQ (name, ".MIPS.post_rel"))
return FALSE;
break;
+ case SHT_MIPS_XHASH:
+ if (strcmp (name, ".MIPS.xhash") != 0)
+ return FALSE;
default:
break;
}
@@ -7708,6 +7738,12 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
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
@@ -7994,6 +8030,11 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
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
@@ -10176,6 +10217,10 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd,
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;
@@ -11953,6 +11998,12 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
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
@@ -12440,6 +12491,10 @@ _bfd_mips_final_write_processing (bfd *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;
}
}
}
@@ -15943,6 +15998,8 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag)
return "DT_MIPS_PLTGOT";
case DT_MIPS_RWPLT:
return "DT_MIPS_RWPLT";
+ case DT_MIPS_XHASH:
+ return "DT_MIPS_XHASH";
}
}
@@ -16276,6 +16333,7 @@ const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] =
{ 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 }
};
@@ -16590,6 +16648,7 @@ enum
MIPS_LIBC_ABI_UNIQUE,
MIPS_LIBC_ABI_MIPS_O32_FP64,
MIPS_LIBC_ABI_ABSOLUTE,
+ MIPS_LIBC_ABI_XHASH,
MIPS_LIBC_ABI_MAX
};
@@ -16617,6 +16676,11 @@ _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info)
if (htab != NULL && htab->use_absolute_zero && htab->gnu_target)
i_ehdrp->e_ident[EI_ABIVERSION] = MIPS_LIBC_ABI_ABSOLUTE;
+ /* 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;
+
_bfd_elf_post_process_headers (abfd, link_info);
}
@@ -16635,3 +16699,17 @@ _bfd_mips_elf_cant_unwind_opcode
{
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;
+}
diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h
index 0a901c6..8e796a9 100644
--- a/bfd/elfxx-mips.h
+++ b/bfd/elfxx-mips.h
@@ -173,6 +173,9 @@ extern bfd_boolean _bfd_mips_elf_common_definition (Elf_Internal_Sym *);
extern int _bfd_mips_elf_compact_eh_encoding (struct bfd_link_info *);
extern int _bfd_mips_elf_cant_unwind_opcode (struct bfd_link_info *);
+extern void _bfd_mips_elf_record_xhash_symbol
+ (struct elf_link_hash_entry *h, bfd_vma xlat_loc);
+
static inline bfd_boolean
gprel16_reloc_p (unsigned int r_type)
{
@@ -198,4 +201,5 @@ literal_reloc_p (int r_type)
#define elf_backend_post_process_headers _bfd_mips_post_process_headers
#define elf_backend_compact_eh_encoding _bfd_mips_elf_compact_eh_encoding
#define elf_backend_cant_unwind_opcode _bfd_mips_elf_cant_unwind_opcode
+#define elf_backend_record_xhash_symbol _bfd_mips_elf_record_xhash_symbol
#define elf_backend_always_renumber_dynsyms TRUE
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index aecc60f..0b737a4 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -734,6 +734,10 @@
#define elf_backend_hash_symbol _bfd_elf_hash_symbol
#endif
+#ifndef elf_backend_record_xhash_symbol
+#define elf_backend_record_xhash_symbol NULL
+#endif
+
#ifndef elf_backend_is_function_type
#define elf_backend_is_function_type _bfd_elf_is_function_type
#endif
@@ -858,6 +862,7 @@ static struct elf_backend_data elfNN_bed =
elf_backend_common_section,
elf_backend_merge_symbol,
elf_backend_hash_symbol,
+ elf_backend_record_xhash_symbol,
elf_backend_is_function_type,
elf_backend_maybe_function_sym,
elf_backend_get_reloc_section,
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 22406f6..54dbf9a 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,13 @@
+2019-08-09 Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
+
+ * readelf.c (get_mips_dynamic_type): Return MIPS_XHASH dynamic type.
+ (get_mips_section_type_name): Return MI{S_XHASH name string.
+ (dynamic_section_mips_val): Initialize the .MIPS.xhash dynamic
+ info.
+ (process_symbol_table): Initialize the .MIPS.xhash section
+ pointer. Adjust the readelf output to support the new section.
+ (process_object): Set the .MIPS.xhash dynamic info to zero.
+
2019-08-09 Tamar Christina <tamar.christina@arm.com>
* testsuite/binutils-all/arm/in-order-all.d: Skip on pe, wince, coff.
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 5bfbac9..b90d3bc 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -232,6 +232,7 @@ static unsigned int dynamic_syminfo_nent;
static char program_interpreter[PATH_MAX];
static bfd_vma dynamic_info[DT_ENCODING];
static bfd_vma dynamic_info_DT_GNU_HASH;
+static bfd_vma dynamic_info_DT_MIPS_XHASH;
static bfd_vma version_info[16];
static Elf_Internal_Dyn * dynamic_section;
static elf_section_list * symtab_shndx_list;
@@ -335,6 +336,10 @@ static const char * get_symbol_version_string
(ADDR) &= ~1; \
} \
while (0)
+
+/* Get the correct GNU hash section name. */
+#define GNU_HASH_SECTION_NAME \
+ dynamic_info_DT_MIPS_XHASH ? ".MIPS.xhash" : ".gnu.hash"
/* Print a BFD_VMA to an internal buffer, for use in error messages.
BFD_FMA_FMT can't be used in translated strings. */
@@ -1872,6 +1877,7 @@ get_mips_dynamic_type (unsigned long type)
case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC";
case DT_MIPS_PLTGOT: return "MIPS_PLTGOT";
case DT_MIPS_RWPLT: return "MIPS_RWPLT";
+ case DT_MIPS_XHASH: return "MIPS_XHASH";
default:
return NULL;
}
@@ -4113,6 +4119,7 @@ get_mips_section_type_name (unsigned int sh_type)
case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD";
case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";
case SHT_MIPS_ABIFLAGS: return "MIPS_ABIFLAGS";
+ case SHT_MIPS_XHASH: return "MIPS_XHASH";
default:
break;
}
@@ -9525,6 +9532,11 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry)
print_vma (entry->d_un.d_val, DEC);
break;
+ case DT_MIPS_XHASH:
+ dynamic_info_DT_MIPS_XHASH = entry->d_un.d_val;
+ dynamic_info_DT_GNU_HASH = entry->d_un.d_val;
+ /* Falls through. */
+
default:
print_vma (entry->d_un.d_ptr, PREFIX_HEX);
}
@@ -11673,6 +11685,7 @@ process_symbol_table (Filedata * filedata)
bfd_vma ngnubuckets = 0;
bfd_vma * gnubuckets = NULL;
bfd_vma * gnuchains = NULL;
+ bfd_vma * mipsxlat = NULL;
bfd_vma gnusymidx = 0;
bfd_size_type ngnuchains = 0;
@@ -11838,7 +11851,31 @@ process_symbol_table (Filedata * filedata)
gnuchains = get_dynamic_data (filedata, maxchain, 4);
ngnuchains = maxchain;
+ if (gnuchains == NULL)
+ goto no_gnu_hash;
+
+ if (dynamic_info_DT_MIPS_XHASH)
+ {
+ if (fseek (filedata->handle,
+ (archive_file_offset
+ + offset_from_vma (filedata, (buckets_vma
+ + 4 * (ngnubuckets
+ + maxchain)), 4)),
+ SEEK_SET))
+ {
+ error (_("Unable to seek to start of dynamic information\n"));
+ goto no_gnu_hash;
+ }
+
+ mipsxlat = get_dynamic_data (filedata, maxchain, 4);
+ }
+
no_gnu_hash:
+ if (dynamic_info_DT_MIPS_XHASH && mipsxlat == NULL)
+ {
+ free (gnuchains);
+ gnuchains = NULL;
+ }
if (gnuchains == NULL)
{
free (gnubuckets);
@@ -11888,7 +11925,8 @@ process_symbol_table (Filedata * filedata)
if (dynamic_info_DT_GNU_HASH)
{
- printf (_("\nSymbol table of `.gnu.hash' for image:\n"));
+ printf (_("\nSymbol table of `%s' for image:\n"),
+ GNU_HASH_SECTION_NAME);
if (is_32bit_elf)
printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n"));
else
@@ -11902,7 +11940,10 @@ process_symbol_table (Filedata * filedata)
do
{
- print_dynamic_symbol (filedata, si, hn);
+ if (dynamic_info_DT_MIPS_XHASH)
+ print_dynamic_symbol (filedata, mipsxlat[off], hn);
+ else
+ print_dynamic_symbol (filedata, si, hn);
si++;
}
while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
@@ -12125,11 +12166,12 @@ process_symbol_table (Filedata * filedata)
unsigned long nzero_counts = 0;
unsigned long nsyms = 0;
- printf (ngettext ("\nHistogram for `.gnu.hash' bucket list length "
+ printf (ngettext ("\nHistogram for `%s' bucket list length "
"(total of %lu bucket):\n",
- "\nHistogram for `.gnu.hash' bucket list length "
+ "\nHistogram for `%s' bucket list length "
"(total of %lu buckets):\n",
(unsigned long) ngnubuckets),
+ GNU_HASH_SECTION_NAME,
(unsigned long) ngnubuckets);
lengths = (unsigned long *) calloc (ngnubuckets, sizeof (*lengths));
@@ -12186,6 +12228,7 @@ process_symbol_table (Filedata * filedata)
free (lengths);
free (gnubuckets);
free (gnuchains);
+ free (mipsxlat);
}
return TRUE;
@@ -19744,6 +19787,7 @@ process_object (Filedata * filedata)
for (i = ARRAY_SIZE (dynamic_info); i--;)
dynamic_info[i] = 0;
dynamic_info_DT_GNU_HASH = 0;
+ dynamic_info_DT_MIPS_XHASH = 0;
/* Process the file. */
if (show_name)
diff --git a/include/ChangeLog b/include/ChangeLog
index 9d55a1f2..1813cb3 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2019-08-09 Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
+
+ * elf/mips.h (SHT_GNU_XHASH): New define.
+ (DT_GNU_XHASH): New define.
+
2019-08-08 Yoshinori Sato <ysato@users.sourceforge.jp>
* opcode/h8300.h (EXPAND_UNOP_EXTENDED_B): Add MODEL.
diff --git a/include/elf/mips.h b/include/elf/mips.h
index b76d450..cd6779f 100644
--- a/include/elf/mips.h
+++ b/include/elf/mips.h
@@ -452,6 +452,9 @@ END_RELOC_NUMBERS (R_MIPS_maxext)
/* ABI related flags section. */
#define SHT_MIPS_ABIFLAGS 0x7000002a
+/* GNU style symbol hash table with xlat. */
+#define SHT_MIPS_XHASH 0x7000002b
+
/* A section of type SHT_MIPS_LIBLIST contains an array of the
following structure. The sh_link field is the section index of the
string table. The sh_info field is the number of entries in the
@@ -759,6 +762,9 @@ extern void bfd_mips_elf32_swap_reginfo_out
/* Relative offset of run time loader map, used for debugging. */
#define DT_MIPS_RLD_MAP_REL 0x70000035
+
+/* Address of .MIPS.xhash section. */
+#define DT_MIPS_XHASH 0x70000036
/* Flags which may appear in a DT_MIPS_FLAGS entry. */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 3010abb..6ff1a47 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,19 @@
+2019-08-09 Mihailo Stojanovic <mihailo.stojanovic@rt-rk.com>
+
+ * emulparams/elf32bmip.sh: Add .MIPS.xhash section.
+ * emulparams/elf32bmipn32-defs.sh: Add .MIPS.xhash section.
+ * emulparams/elf64bmip-defs.sh: Add .MIPS.xhash section.
+ * emultempl/mipself.em: Remove mips_after_parse function.
+ * testsuite/ld-elf/hash.d: Update comment.
+ * testsuite/ld-mips-elf/hash1.d: New test.
+ * testsuite/ld-mips-elf/hash1.s: Ditto.
+ * testsuite/ld-mips-elf/hash1a.d: Remove.
+ * testsuite/ld-mips-elf/hash1b.d: Ditto.
+ * testsuite/ld-mips-elf/hash1c.d: Ditto
+ * testsuite/ld-mips-elf/hash2.d: New test.
+ * testsuite/ld-mips-elf/mips-elf.exp: New tests.
+ * testsuite/ld-mips-elf/start.s: New test.
+
2019-08-08 Nick Clifton <nickc@redhat.com>
PR 24887
diff --git a/ld/emulparams/elf32bmip.sh b/ld/emulparams/elf32bmip.sh
index abbcb5b..1e0200a 100644
--- a/ld/emulparams/elf32bmip.sh
+++ b/ld/emulparams/elf32bmip.sh
@@ -19,6 +19,7 @@ fi
INITIAL_READONLY_SECTIONS="${INITIAL_READONLY_SECTIONS}
.MIPS.abiflags ${RELOCATING-0} : { *(.MIPS.abiflags) }
.reginfo ${RELOCATING-0} : { *(.reginfo) }
+ .MIPS.xhash ${RELOCATING-0} : { *(.MIPS.xhash) }
"
OTHER_TEXT_SECTIONS='*(.mips16.fn.*) *(.mips16.call.*)'
# Unlike most targets, the MIPS backend puts all dynamic relocations
diff --git a/ld/emulparams/elf32bmipn32-defs.sh b/ld/emulparams/elf32bmipn32-defs.sh
index bd01790..80dce8f 100644
--- a/ld/emulparams/elf32bmipn32-defs.sh
+++ b/ld/emulparams/elf32bmipn32-defs.sh
@@ -87,6 +87,7 @@ if test -z "${CREATE_SHLIB}"; then
fi
INITIAL_READONLY_SECTIONS="${INITIAL_READONLY_SECTIONS}
.MIPS.abiflags ${RELOCATING-0} : { *(.MIPS.abiflags) }
+ .MIPS.xhash ${RELOCATING-0} : { *(.MIPS.xhash) }
.reginfo ${RELOCATING-0} : { *(.reginfo) }"
# Discard any .MIPS.content* or .MIPS.events* sections. The linker
# doesn't know how to adjust them.
diff --git a/ld/emulparams/elf64bmip-defs.sh b/ld/emulparams/elf64bmip-defs.sh
index 61d6c00..4165f51 100644
--- a/ld/emulparams/elf64bmip-defs.sh
+++ b/ld/emulparams/elf64bmip-defs.sh
@@ -2,5 +2,6 @@ source_sh ${srcdir}/emulparams/elf32bmipn32-defs.sh
COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)"
INITIAL_READONLY_SECTIONS="
.MIPS.abiflags ${RELOCATING-0} : { *(.MIPS.abiflags) }
+ .MIPS.xhash ${RELOCATING-0} : { *(.MIPS.xhash) }
.MIPS.options : { *(.MIPS.options) }
"
diff --git a/ld/emultempl/mipself.em b/ld/emultempl/mipself.em
index ec908d7..fe46e0d 100644
--- a/ld/emultempl/mipself.em
+++ b/ld/emultempl/mipself.em
@@ -46,21 +46,6 @@ static bfd_boolean insn32;
static bfd_boolean ignore_branch_isa;
static bfd_boolean compact_branches;
-static void
-mips_after_parse (void)
-{
- /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different
- ways. .gnu.hash needs symbols to be grouped by hash code whereas the
- MIPS ABI requires a mapping between the GOT and the symbol table. */
- if (link_info.emit_gnu_hash)
- {
- einfo (_("%X%P: .gnu.hash is incompatible with the MIPS ABI\n"));
- link_info.emit_hash = TRUE;
- link_info.emit_gnu_hash = FALSE;
- }
- gld${EMULATION_NAME}_after_parse ();
-}
-
struct hook_stub_info
{
lang_statement_list_type add;
@@ -337,6 +322,5 @@ PARSE_AND_LIST_ARGS_CASES='
break;
'
-LDEMUL_AFTER_PARSE=mips_after_parse
LDEMUL_BEFORE_ALLOCATION=mips_before_allocation
LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=mips_create_output_section_statements
diff --git a/ld/testsuite/ld-elf/hash.d b/ld/testsuite/ld-elf/hash.d
index fb07912..efe675e 100644
--- a/ld/testsuite/ld-elf/hash.d
+++ b/ld/testsuite/ld-elf/hash.d
@@ -3,7 +3,7 @@
#ld: -shared --hash-style=gnu
#target: *-*-linux* *-*-gnu* arm*-*-uclinuxfdpiceabi
#xfail: mips*-*-*
-# GNU hash is not supported for MIPS targets due to psABI restrictions
+# MIPS uses a different style of GNU hash due to psABI restrictions
# on dynsym table ordering.
#...
diff --git a/ld/testsuite/ld-mips-elf/hash1.d b/ld/testsuite/ld-mips-elf/hash1.d
new file mode 100644
index 0000000..3b9725d
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/hash1.d
@@ -0,0 +1,11 @@
+#source: hash1.s
+#readelf: -d -I
+#ld: -nostdlib -shared --hash-style=gnu
+#target: [check_shared_lib_support]
+#xfail: mips*-*-irix*
+
+#...
+ +0x[0-9a-z]+ +\(MIPS_XHASH\) +0x[0-9a-z]+
+#...
+ +1 +1 +\( 50.0%\) +100.0%
+#...
diff --git a/ld/testsuite/ld-mips-elf/hash1.s b/ld/testsuite/ld-mips-elf/hash1.s
index 4e7fe2f..587cef1 100644
--- a/ld/testsuite/ld-mips-elf/hash1.s
+++ b/ld/testsuite/ld-mips-elf/hash1.s
@@ -1 +1,7 @@
- nop
+.globl foo
+
+.text
+
+foo:
+ jr $ra
+ nop
diff --git a/ld/testsuite/ld-mips-elf/hash1a.d b/ld/testsuite/ld-mips-elf/hash1a.d
deleted file mode 100644
index c189c93..0000000
--- a/ld/testsuite/ld-mips-elf/hash1a.d
+++ /dev/null
@@ -1,5 +0,0 @@
-#source: hash1.s
-#ld: -shared --hash-style=sysv
-#objdump: -dr
-#target: [check_shared_lib_support]
-#pass
diff --git a/ld/testsuite/ld-mips-elf/hash1b.d b/ld/testsuite/ld-mips-elf/hash1b.d
deleted file mode 100644
index 5cafede..0000000
--- a/ld/testsuite/ld-mips-elf/hash1b.d
+++ /dev/null
@@ -1,4 +0,0 @@
-#source: hash1.s
-#ld: -shared --hash-style=both
-#target: [check_shared_lib_support]
-#error: .gnu.hash is incompatible with the MIPS ABI
diff --git a/ld/testsuite/ld-mips-elf/hash1c.d b/ld/testsuite/ld-mips-elf/hash1c.d
deleted file mode 100644
index 379620a..0000000
--- a/ld/testsuite/ld-mips-elf/hash1c.d
+++ /dev/null
@@ -1,4 +0,0 @@
-#source: hash1.s
-#ld: -shared --hash-style=gnu
-#target: [check_shared_lib_support]
-#error: .gnu.hash is incompatible with the MIPS ABI
diff --git a/ld/testsuite/ld-mips-elf/hash2.d b/ld/testsuite/ld-mips-elf/hash2.d
new file mode 100644
index 0000000..79fda3c
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/hash2.d
@@ -0,0 +1,17 @@
+#source: start.s
+#readelf: -d -s -D
+#ld: -shared --hash-style=gnu
+#target: [check_shared_lib_support]
+#xfail: mips*-*-irix*
+
+#...
+ +0x[0-9a-z]+ +\(MIPS_XHASH\) +0x[0-9a-z]+
+#...
+ +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] _start
+#...
+ +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] main
+#...
+ +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] start
+#...
+ +[0-9]+ +[0-9]+: +[0-9a-f]+ +[0-9]+ +NOTYPE +GLOBAL +DEFAULT +[1-9] __start
+#...
diff --git a/ld/testsuite/ld-mips-elf/mips-elf.exp b/ld/testsuite/ld-mips-elf/mips-elf.exp
index 1fee8ef..3c7ce6a 100644
--- a/ld/testsuite/ld-mips-elf/mips-elf.exp
+++ b/ld/testsuite/ld-mips-elf/mips-elf.exp
@@ -854,9 +854,8 @@ if { $linux_gnu } {
run_dump_test_n32 "emit-relocs-1" {{as -EB} {ld -EB}}
-run_dump_test "hash1a"
-run_dump_test "hash1b"
-run_dump_test "hash1c"
+run_dump_test "hash1"
+run_dump_test "hash2"
if { $linux_gnu && $has_abi(o32) } {
# The number of symbols that are always included in the symbol table
diff --git a/ld/testsuite/ld-mips-elf/start.s b/ld/testsuite/ld-mips-elf/start.s
new file mode 100644
index 0000000..ee26ab3
--- /dev/null
+++ b/ld/testsuite/ld-mips-elf/start.s
@@ -0,0 +1,12 @@
+ .text
+ .globl start
+start:
+ .globl _start
+_start:
+ .globl __start
+__start:
+ .globl main
+main:
+ .globl _main
+_main:
+ .dc.a 0