diff options
-rw-r--r-- | bfd/ChangeLog | 46 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 7 | ||||
-rw-r--r-- | bfd/elflink.c | 46 | ||||
-rw-r--r-- | bfd/elfxx-mips.c | 78 | ||||
-rw-r--r-- | bfd/elfxx-mips.h | 4 | ||||
-rw-r--r-- | bfd/elfxx-target.h | 5 | ||||
-rw-r--r-- | binutils/ChangeLog | 10 | ||||
-rw-r--r-- | binutils/readelf.c | 52 | ||||
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/elf/mips.h | 6 | ||||
-rw-r--r-- | ld/ChangeLog | 16 | ||||
-rw-r--r-- | ld/emulparams/elf32bmip.sh | 1 | ||||
-rw-r--r-- | ld/emulparams/elf32bmipn32-defs.sh | 1 | ||||
-rw-r--r-- | ld/emulparams/elf64bmip-defs.sh | 1 | ||||
-rw-r--r-- | ld/emultempl/mipself.em | 16 | ||||
-rw-r--r-- | ld/testsuite/ld-elf/hash.d | 2 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash1.d | 11 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash1.s | 8 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash1a.d | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash1b.d | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash1c.d | 4 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/hash2.d | 17 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/mips-elf.exp | 5 | ||||
-rw-r--r-- | ld/testsuite/ld-mips-elf/start.s | 12 |
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 |