This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
Hi, I have revised the patch with more suggestions from the previous discussions. Detailed description is in the attached text file. I think I have got a better handle on symbol preemption with this version, but I would really appreciate some input on that aspect. Previous discussions for reference: https://www.sourceware.org/ml/binutils/2013-08/msg00121.html https://www.sourceware.org/ml/binutils/2013-11/msg00155.html https://sourceware.org/ml/binutils/2013-12/msg00058.html Tests have been split out in to a separate patch and attached for review. These are carried forward from the previous iteration. I am working on translating more of my informal tests to the correct format. Regards, Faraz Shahbazker bfd/ChangeLog: * bfd-in2.h (BFD_RELOC_MIPS_IRELATIVE): New relocation. * elf32-mips.c (elf_mips_eh_howto table): Howto for BFD_RELOC_MIPS_IRELATIVE. (bfd_elf32_bfd_reloc_type_lookup): Case for R_MIPS_IRELATIVE. (bfd_elf32_bfd_reloc_name_lookup): Case for R_MIPS_IRELATIVE. (mips_elf32_rtype_to_howto): Case for R_MIPS_IRELATIVE * elfxx-mips.c (struct mips_got_info): New fields general_gotno and assigned_general_gotno. (struct mips_elf_link_hash_entry): New fields for offset in to IPLT/IGOT and flags to indicate symbol needs IPLT or IRELOC. (mips_elf_link_hash_table): New fields for size of IPLT stubs and hash-table for local IFUNC symbols. (MIPS16_P): New macro to check ASE flag. (mips16_exec_iplt_entry): Template for mips16 IPLT stub. (mips32_exec_iplt_entry): Template for mips32 IPLT stub. (mips32r6_exec_iplt_entry): Template for mips32 R6 IPLT stub. (micromips32_exec_iplt_entry): Template for micromips32 stub. (mips64_exec_iplt_entry): Template for mips64 IPLT stub. (mips64_48b_exec_iplt_entry): Template for mips64 IPLT stub. (mips_elf_link_hash_newfunc): Initialization of new mips_elf_link_hash_entry elements. (mips_elf_create_stub_symbol): Set ISA bit in address and ST_MIPS16 type for mips16 IPLT stubs. (mips_elf_rel_dyn_section): Moved up to avoid forward declaration. (mips_get_irel_section): New function. (mips_elf_allocate_ireloc): Likewise. (mips_elf_allocate_iplt): Likewise. (mips_elf_check_local_symbols): Likewise. (mips_elf_check_symbols): Allocate an IPLT entry and/or dynamic relocation for IFUNC symbols. (mips_elf_count_got_entry): Count local IFUNCs under general GOT entries instead of local. (mips_elf_got16_entry): Add argument h and pass it to mips_elf_create_local_got_entry instead of NULL. (mips_elf_create_local_got_entry): Add check for sufficient general GOT entries. Assign local IFUNCs from general GOT entries pool. (mips_elf_count_general_got_symbols): New function. (mips_elf_deallocate_irelocs): Likewise. (mips_elf_multi_got): Traverse primary GOT entries and deallocate previously allocated IRELOCs for symbols marked RELOC_ONLY. (mips_elf_create_ifunc_sections): New function. (get_local_sym_hash): Likewise. (mips_elf_calculate_relocation): Create hash-table for local IFUNC symbols and condition them to be accessed through GOT. Point IFUNC symbol value to IPLT stub for symbols that need IPLT. (mips_elf_create_dynamic_relocation): Emit IRELATIVE relocation instead of REL32 for local IFUNC reference. (_bfd_mips_elf_section_processing): Size .igot section. (_bfd_mips_elf_add_symbol_hook): Mark output as has_gnu_symbols. (_bfd_mips_elf_check_relocs): Check need to create IFUNC sections. If symbol is an IFUNC, don't convert it to an STT_FUNC. Relax error checking to allow local IFUNCs to be accessed via call16 reloc. (_bfd_mips_elf_adjust_dynamic_symbol): Add STT_GNU_IFUNC to sanity check. (_bfd_mips_elf_always_size_sections): Allocate relocs for local IFUNCs. (mips_elf_lay_out_got): Count general GOT entries. Offset local entries to follow general entries. (_bfd_mips_elf_size_dynamic_sections): Exclude IPLT and IGOT. Create dynamic tag for DT_MIPS_GENERAL_GOTNO if needed. (_bfd_mips_elf_relocate_section): Relax error checking to allow local IFUNCs to be accessed via standalone got16 reloc. (mips_elf_create_iplt): New function. (misp_elf_check_local_got_index): Likewise. (mips_elf_create_ireloc): Likewise. (_bfd_mips_elf_finish_dynamic_symbol): Create IPLT stub/IREL relocation for IFUNC symbols as necessary. Set IFUNC symbol value to the IPLT entry address for executable objects. (_bfd_mips_elf_finish_local_dynamic_symbol): New function. (_bfd_mips_elf_finish_dynamic_sections): Call _bfd_mips_elf_finish_local_dynamic_symbol for all local IFUNCs. Set values of dynamic tag - DT_MIPS_GENERAL_GOTNO. (local_htab_hash): New function, hash table for local IFUNCs. (loc_htab_eq): New comparison function for local IFUNC hash table. (_bfd_mips_elf_link_hash_table_free): New function. (_bfd_mips_elf_link_hash_table_create): Allocate a hash table for local IFUNCs. ( _bfd_mips_elf_get_target_dtag): Add cases for dynamic tag - DT_MIPS_GENERAL_GOTNO. * libbfd.h (bfd_reloc_code_real_names): Entry for BFD_RELOC_MIPS_IRELATIVE. * reloc.c (ENUMDOC): BFD_RELOC_MIPS_IRELATIVE entry. binutils/ChangeLog: * readelf.c: (get_mips_dynamic_type): Add case for DT_MIPS_GENERAL_GOTNO. (dynamic_section_mips_val): Add case for DT_MIPS_GENERAL_GOTNO. elfcpp/ChangeLog: * elfcpp.h (enum DT): Add cases for dynamic tag DT_MIPS_GENERAL_GOTNO. include/elf/ChangeLog: * mips.h (START_RELOC_NUMBERS): Entry for R_MIPS_IRELATIVE. (DT_MIPS_GENERAL_GOTNO): New dynamic tag. --- bfd/bfd-in2.h | 3 + bfd/elf32-mips.c | 22 ++ bfd/elfxx-mips.c | 991 ++++++++++++++++++++++++++++++++++++++++++++++++---- bfd/libbfd.h | 1 + bfd/reloc.c | 5 + binutils/readelf.c | 3 + elfcpp/elfcpp.h | 2 + include/elf/mips.h | 7 + 8 files changed, 964 insertions(+), 70 deletions(-) diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index c27db8d..7eec1b5 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3038,6 +3038,9 @@ to compensate for the borrow when the low bits are added. */ BFD_RELOC_MIPS_JUMP_SLOT, +/* MIPS support for STT_GNU_IFUNC. */ + BFD_RELOC_MIPS_IRELATIVE, + /* Moxie ELF relocations. */ BFD_RELOC_MOXIE_10_PCREL, diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index fff08e5..7f9c9b4 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -1646,6 +1646,22 @@ static reloc_howto_type elf_mips_eh_howto = 0xffffffff, /* dst_mask */ FALSE); /* pcrel_offset */ +/* STT_GNU_IFUNC support: */ +static reloc_howto_type elf_mips_irelative_howto = + HOWTO (R_MIPS_IRELATIVE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield,/* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_IRELATIVE", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE); /* pcrel_offset */ + /* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a dangerous relocation. */ @@ -2126,6 +2142,8 @@ bfd_elf32_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code) return &elf_mips_jump_slot_howto; case BFD_RELOC_MIPS_EH: return &elf_mips_eh_howto; + case BFD_RELOC_MIPS_IRELATIVE: + return &elf_mips_irelative_howto; } } @@ -2173,6 +2191,8 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, return &elf_mips_jump_slot_howto; if (strcasecmp (elf_mips_eh_howto.name, r_name) == 0) return &elf_mips_eh_howto; + if (strcasecmp (elf_mips_irelative_howto.name, r_name) == 0) + return &elf_mips_irelative_howto; return NULL; } @@ -2199,6 +2219,8 @@ mips_elf32_rtype_to_howto (unsigned int r_type, return &elf_mips_jump_slot_howto; case R_MIPS_EH: return &elf_mips_eh_howto; + case R_MIPS_IRELATIVE: + return &elf_mips_irelative_howto; default: if (r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max) return &elf_micromips_howto_table_rel[r_type - R_MICROMIPS_min]; diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 9932453..521fcd6 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -45,6 +45,7 @@ #include "coff/mips.h" #include "hashtab.h" +#include "objalloc.h" /* Types of TLS GOT entry. */ enum mips_got_tls_type { @@ -165,10 +166,14 @@ struct mips_got_info unsigned int tls_assigned_gotno; /* The number of local .got entries, eventually including page entries. */ unsigned int local_gotno; + /* The number of explicitly relocated .got entries. */ + unsigned int general_gotno; /* The maximum number of page entries needed. */ unsigned int page_gotno; /* The number of relocations needed for the GOT entries. */ unsigned int relocs; + /* The first unused general .got entry. */ + unsigned int assigned_general_gotno; /* The first unused local .got entry. */ unsigned int assigned_low_gotno; /* The last unused local .got entry. */ @@ -375,6 +380,12 @@ struct mips_elf_link_hash_entry being called returns a floating point value. */ asection *call_fp_stub; + /* Offset into the IPLT table. */ + bfd_vma iplt_offset; + + /* Offset into the IGOT table. */ + bfd_vma igot_offset; + /* The highest GGA_* value that satisfies all references to this symbol. */ unsigned int global_got_area : 2; @@ -413,6 +424,12 @@ struct mips_elf_link_hash_entry /* Does this symbol resolve to a PLT entry? */ unsigned int use_plt_entry : 1; + + /* Does this symbol need an IPLT stub? */ + unsigned int needs_iplt : 1; + + /* Does this ifunc symbol need an IGOT entry? */ + unsigned int needs_ireloc : 1; }; /* MIPS ELF linker hash table. */ @@ -485,6 +502,9 @@ struct mips_elf_link_hash_table /* The index of the next .got.plt entry to create. */ bfd_vma plt_got_index; + /* The size of an IPLT entry in bytes. */ + bfd_vma iplt_entry_size; + /* The number of functions that need a lazy-binding stub. */ bfd_vma lazy_stub_count; @@ -516,6 +536,10 @@ struct mips_elf_link_hash_table /* Is the PLT header compressed? */ unsigned int plt_header_is_comp : 1; + + /* Used by local STT_GNU_IFUNC symbols. */ + htab_t loc_hash_table; + void *loc_hash_memory; }; /* Get the MIPS ELF linker hash table from a link_info structure. */ @@ -800,6 +824,10 @@ static bfd *reldyn_sorting_bfd; #define MICROMIPS_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS) != 0) +/* Nonzero if ABFD has mips16 code. */ +#define MIPS16_P(abfd) \ + ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16) != 0) + /* Nonzero if ABFD is MIPS R6. */ #define MIPSR6_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R6 \ @@ -1191,6 +1219,69 @@ static const bfd_vma mips_vxworks_shared_plt_entry[] = 0x10000000, /* b .PLT_resolver */ 0x24180000 /* li t8, <pltindex> */ }; + +/* The format of MIPS16 o32 IPLT entries. We use v0 ($2) + and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not + directly addressable. */ +static const bfd_vma mips16_exec_iplt_entry[] = +{ + 0xb202, /* lw $2, 8($pc) */ + 0x9a60, /* lw $3, 0($2) */ + 0xeb00, /* jr $3 */ + 0x653b, /* move $25, $3 */ + 0x0000, 0x0000 /* .word (.igot address) */ +}; + +/* The format of 32 bit IPLT entries. */ +static const bfd_vma mips32_exec_iplt_entry[] = +{ + 0x3c0f0000, /* lui $15, %hi(.igot address) */ + 0x8df90000, /* lw $25, %lo(.igot address)($15) */ + 0x03200008, /* jr $25 */ + 0x00000000 /* nop */ +}; + +/* Format of 32 bit IPLT entries for R6. JR encoding differs. */ +static const bfd_vma mips32r6_exec_iplt_entry[] = +{ + 0x3c0f0000, /* lui $15, %hi(.igot address) */ + 0x8df90000, /* lw $25, %lo(.igot address)($15) */ + 0x03200009, /* jr $25 */ + 0x00000000 /* nop */ +}; + +/* The format of 32-bit micromips IPLT entries. */ +static const bfd_vma micromips32_exec_iplt_entry[] = +{ + 0x41a30000, /* lui $2, %hi(.igot address) */ + 0xff230000, /* ld $2, %lo(.igot address)($2) */ + 0x4599, /* jr $25 */ + 0x0c00, /* nop */ +}; + +/* The format of 64-bit IPLT entries. */ +static const bfd_vma mips64_exec_iplt_entry[] = +{ + 0x3c0f0000, /* lui $15, %highest(.got.iplt entry) */ + 0x3c0e0000, /* lui $14, %hi(.got.iplt entry) */ + 0x25ef0000, /* addiu $15, $15, %higher(.got.iplt entry) */ + 0x000f783c, /* dsll32 $15, $15, 0x0 */ + 0x01ee782d, /* daddu $15, $15, $14 */ + 0xddf90000, /* ld $25, %lo(.got.iplt entry)($15) */ + 0x03200008, /* jr $25 */ + 0x00000000, /* nop */ +}; + +static const bfd_vma mips64_48b_exec_iplt_entry[] = +{ + 0x3c0f0000, /* lui $15, %higher(.got.iplt entry) */ + 0x25ef0000, /* addiu $15, $15, %high(.got.iplt entry) */ + 0x000f7c38, /* dsll $15, $15, 16 */ + 0xddf90000, /* ld $25, %lo(.got.iplt entry)($15) */ + 0x03200008, /* jr $25 */ + 0x00000000, /* nop */ +}; + ? /* microMIPS 32-bit opcode helper installer. */ @@ -1289,6 +1380,10 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, ret->has_nonpic_branches = FALSE; ret->needs_lazy_stub = FALSE; ret->use_plt_entry = FALSE; + ret->needs_iplt = FALSE; + ret->needs_ireloc = FALSE; + ret->iplt_offset = -1; + ret->igot_offset = 0; } return (struct bfd_hash_entry *) ret; @@ -1588,8 +1683,9 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *elfh; const char *name; - if (ELF_ST_IS_MICROMIPS (h->root.other)) - value |= 1; + if (ELF_ST_IS_MICROMIPS (h->root.other) + || (ELF_ST_IS_MIPS16 (h->root.other) && h->root.type == STT_GNU_IFUNC)) + value |= 1; /* Create a new symbol. */ name = ACONCAT ((prefix, h->root.root.root.string, NULL)); @@ -1604,6 +1700,10 @@ mips_elf_create_stub_symbol (struct bfd_link_info *info, elfh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC); elfh->size = size; elfh->forced_local = 1; + + if (ELF_ST_IS_MIPS16 (h->root.other) && h->needs_iplt) + elfh->other = STO_MIPS16; + return TRUE; } @@ -1966,6 +2066,137 @@ mips_elf_add_la25_stub (struct bfd_link_info *info, : mips_elf_add_la25_intro (stub, info)); } +/* Return the dynamic relocation section. If it doesn't exist, try to + create a new it if CREATE_P, otherwise return NULL. Also return NULL + if creation fails. */ + +static asection * +mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p) +{ + const char *dname; + asection *sreloc; + bfd *dynobj; + + dname = MIPS_ELF_REL_DYN_NAME (info); + dynobj = elf_hash_table (info)->dynobj; + sreloc = bfd_get_linker_section (dynobj, dname); + if (sreloc == NULL && create_p) + { + sreloc = bfd_make_section_anyway_with_flags (dynobj, dname, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); + if (sreloc == NULL + || !bfd_set_section_alignment (dynobj, sreloc, + MIPS_ELF_LOG_FILE_ALIGN (dynobj))) + return NULL; + } + return sreloc; +} + +/* Return section for R_MIPS_IRELATIVE relocations. If the link is + dynamic, the relocations should go in .dynrel, otherwise they should + go in the special .rel.iplt section. */ + +static asection * +mips_get_irel_section (struct bfd_link_info *info, + struct mips_elf_link_hash_table *htab) +{ + asection *srel = (elf_hash_table (info)->dynamic_sections_created) + ? mips_elf_rel_dyn_section (info, FALSE) + : htab->root.irelplt; + BFD_ASSERT (srel != NULL); + return srel; +} + +/* Reserve space in the rel.iplt section for IRELATIVE relocation. */ + +static bfd_boolean +mips_elf_allocate_ireloc (struct bfd_link_info *info, + struct mips_elf_link_hash_table *mhtab, + struct mips_elf_link_hash_entry *mh) +{ + asection *srel; + bfd *dynobj; + + if (mh->needs_iplt || mh->global_got_area == GGA_NORMAL + || mh->root.forced_local) + { + srel = mips_get_irel_section (info, mhtab); + dynobj = elf_hash_table (info)->dynobj; + if (srel != mhtab->root.irelplt && srel->size == 0) + { + /* Make room for a null element. */ + srel->size += MIPS_ELF_REL_SIZE (dynobj); + ++srel->reloc_count; + } + srel->size += MIPS_ELF_REL_SIZE (dynobj); + mh->needs_ireloc = TRUE; + } + + return TRUE; +} + +/* Reserve space in the iplt and igot tables for an ifunc entry +and allocate space for an IRELATIVE relocation. */ + +static bfd_boolean +mips_elf_allocate_iplt (struct bfd_link_info *info, + struct mips_elf_link_hash_table *mhtab, + struct mips_elf_link_hash_entry *mh) +{ + asection *s; + bfd *abfd = info->output_bfd; + + BFD_ASSERT (!mh->needs_iplt); + BFD_ASSERT (mhtab->root.iplt != NULL); + + s = mhtab->root.iplt; + + mh->iplt_offset = s->size; + mips_elf_create_stub_symbol (info, mh, ".iplt.", mhtab->root.iplt, + s->size, mhtab->iplt_entry_size); + s->size += mhtab->iplt_entry_size; + + BFD_ASSERT (mhtab->root.igotplt != NULL); + mh->igot_offset = mhtab->root.igotplt->size; + mhtab->root.igotplt->size += MIPS_ELF_GOT_SIZE (abfd); + mh->needs_iplt = TRUE; + + return TRUE; +} + +/* hash_traverse callback that is called before sizing sections. + DATA points to a mips_htab_traverse_info structure. */ + +static bfd_boolean +mips_elf_check_local_symbols (void **slot, void *data) +{ + struct mips_htab_traverse_info *hti = + (struct mips_htab_traverse_info *) data; + struct mips_elf_link_hash_entry *h = + (struct mips_elf_link_hash_entry *) *slot; + + /* If the referenced symbol is ifunc, allocate an iplt for it. */ + if (h && !h->needs_iplt && h->root.type == STT_GNU_IFUNC) + { + struct bfd_link_info *info = hti->info; + /* .iplt entry is needed only for executable objects. */ + if (!info->shared && + !mips_elf_allocate_iplt (info, mips_elf_hash_table (info), h)) + return FALSE; + + /* IRELATIVE fixup will be needed for each local IFUNC. */ + if (!mips_elf_allocate_ireloc (info, mips_elf_hash_table (info), h)) + return FALSE; + } + + return TRUE; +} + /* A mips_elf_link_hash_traverse callback that is called before sizing sections. DATA points to a mips_htab_traverse_info structure. */ @@ -1978,6 +2209,19 @@ mips_elf_check_symbols (struct mips_elf_link_hash_entry *h, void *data) if (!hti->info->relocatable) mips_elf_check_mips16_stubs (hti->info, h); + if (h && !h->needs_iplt && + h->root.type == STT_GNU_IFUNC) + { + struct bfd_link_info *info = hti->info; + /* .iplt entry is needed only for executable objects. */ + if (!info->shared + && !mips_elf_allocate_iplt (info, mips_elf_hash_table (info), h)) + return FALSE; + /* Allocate an extra relocation for this IFUNC, if needed. */ + if (!mips_elf_allocate_ireloc (info, mips_elf_hash_table (info), h)) + return FALSE; + } + if (mips_elf_local_pic_function_p (h)) { /* PR 12845: If H is in a section that has been garbage @@ -3145,37 +3389,6 @@ mips_elf_replace_bfd_got (bfd *abfd, struct mips_got_info *g) tdata->got = g; } -/* Return the dynamic relocation section. If it doesn't exist, try to - create a new it if CREATE_P, otherwise return NULL. Also return NULL - if creation fails. */ - -static asection * -mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p) -{ - const char *dname; - asection *sreloc; - bfd *dynobj; - - dname = MIPS_ELF_REL_DYN_NAME (info); - dynobj = elf_hash_table (info)->dynobj; - sreloc = bfd_get_linker_section (dynobj, dname); - if (sreloc == NULL && create_p) - { - sreloc = bfd_make_section_anyway_with_flags (dynobj, dname, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, - MIPS_ELF_LOG_FILE_ALIGN (dynobj))) - return NULL; - } - return sreloc; -} - /* Return the GOT_TLS_* type required by relocation type R_TYPE. */ static int @@ -3270,7 +3483,14 @@ mips_elf_count_got_entry (struct bfd_link_info *info, ? &entry->d.h->root : NULL); } else if (entry->symndx >= 0 || entry->d.h->global_got_area == GGA_NONE) - g->local_gotno += 1; + { + /* Count IFUNCs as general GOT entries since they will need + explicit IRELATIVE relocations. */ + if (entry->symndx < 0 && entry->d.h->root.type == STT_GNU_IFUNC) + g->general_gotno += 1; + else + g->local_gotno += 1; + } else g->global_gotno += 1; } @@ -3600,7 +3820,8 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, static bfd_vma mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, - bfd_vma value, bfd_boolean external) + bfd_vma value, bfd_boolean external, + struct mips_elf_link_hash_entry *h) { struct mips_got_entry *entry; @@ -3615,7 +3836,7 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, R_MIPS16_GOT16, R_MIPS_CALL16, etc. The format of the entry is the same in all cases. */ entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value, 0, - NULL, R_MIPS_GOT16); + h, R_MIPS_GOT16); if (entry) return entry->gotidx; else @@ -3715,7 +3936,8 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, if (entry) return entry; - if (g->assigned_low_gotno > g->assigned_high_gotno) + if (g->assigned_low_gotno > g->assigned_high_gotno || + g->assigned_general_gotno > g->assigned_low_gotno) { /* We didn't allocate enough space in the GOT. */ (*_bfd_error_handler) @@ -3728,7 +3950,11 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, if (!entry) return NULL; - if (got16_reloc_p (r_type) + if (h && h->root.type == STT_GNU_IFUNC) + /* Allocate IFUNC slots in the general GOT region since they + will need explicit IRELATIVE relocations. */ + lookup.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_general_gotno++; + else if (got16_reloc_p (r_type) || call16_reloc_p (r_type) || got_page_reloc_p (r_type) || got_disp_reloc_p (r_type)) @@ -4460,6 +4686,29 @@ mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) } return 1; } + +/* A elf_link_hash_traverse callback for which INF points to the + link_info structure. Count the number of GOT entries that need + explicit relocations by iterating over the local hash table. */ + +static int +mips_elf_count_general_got_symbols (void **slot, void *inf) +{ + struct mips_elf_link_hash_entry *h = + (struct mips_elf_link_hash_entry *) *slot; + struct bfd_link_info *info; + struct mips_elf_link_hash_table *htab; + struct mips_got_info *g; + + info = (struct bfd_link_info *) inf; + htab = mips_elf_hash_table (info); + + g = htab->got_info; + if (h != NULL && h->root.type == STT_GNU_IFUNC && + (h->root.forced_local || h->global_got_area == GGA_NONE)) + g->general_gotno++; + return 1; +} ? /* A htab_traverse callback for GOT entries. Add each one to the GOT given in mips_elf_traverse_got_arg DATA. Clear DATA->G on error. */ @@ -4698,6 +4947,31 @@ mips_elf_set_global_got_area (void **entryp, void *data) return 1; } +/* A htab_traverse callback for GOT entries, where DATA points to a + mips_elf_traverse_got_arg. Deallocate dedicated REL32 relocations + for global IFUNCs that are marked RELOC_ONLY. */ + +static int +mips_elf_deallocate_irelocs (void **entryp, void *data) +{ + struct mips_got_entry *entry; + + entry = (struct mips_got_entry *) *entryp; + if (entry->abfd != NULL + && entry->symndx == -1 + && entry->d.h->global_got_area == GGA_RELOC_ONLY + && entry->d.h->root.type == STT_GNU_IFUNC + && entry->d.h->needs_ireloc) + { + struct mips_elf_traverse_got_arg *arg + = (struct mips_elf_traverse_got_arg *) data; + asection *srel = mips_elf_rel_dyn_section (arg->info, FALSE); + srel->size -= MIPS_ELF_REL_SIZE (elf_hash_table (arg->info)->dynobj); + entry->d.h->needs_ireloc = FALSE; + } + return 1; +} + /* A htab_traverse callback for secondary GOT entries, where DATA points to a mips_elf_traverse_got_arg. Assign GOT indices to global entries and record the number of relocations they require. DATA->value is @@ -4852,6 +5126,11 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, tga.value = GGA_NORMAL; htab_traverse (g->got_entries, mips_elf_set_global_got_area, &tga); + /* Deallocate extra relocation intended for IFUNCs that have been marked + as RELOC_ONLY. These entries will get explicit relocs due to multi-got + which will work just as well for IFUNC resolution. */ + htab_traverse (gg->got_entries, mips_elf_deallocate_irelocs, &tga); + /* Now go through the GOTs assigning them offset ranges. [assigned_low_gotno, local_gotno[ will be set to the range of local entries in each GOT. We can then compute the end of a GOT by @@ -5087,6 +5366,64 @@ mips_elf_create_compact_rel_section return TRUE; } +/* Create the .iplt, .rel(a).iplt and .igot sections. */ + +static bfd_boolean +mips_elf_create_ifunc_sections (struct bfd_link_info *info) +{ + struct mips_elf_link_hash_table * volatile htab; + const struct elf_backend_data *bed; + bfd *dynobj; + asection *s; + flagword flags; + + htab = mips_elf_hash_table (info); + dynobj = htab->root.dynobj; + bed = get_elf_backend_data (dynobj); + flags = bed->dynamic_sec_flags; + + s = bfd_make_section_anyway_with_flags (dynobj, ".iplt", + flags | SEC_READONLY | SEC_CODE); + if (s == NULL || !bfd_set_section_alignment (dynobj, s, bed->plt_alignment)) + return FALSE; + + htab->root.iplt = s; + + if (!info->shared) + { + if (ABI_64_P (dynobj)) + htab->iplt_entry_size = 4 * ARRAY_SIZE (mips64_exec_iplt_entry); + else if (MIPS16_P (dynobj)) + htab->iplt_entry_size = 2 * ARRAY_SIZE (mips16_exec_iplt_entry); + else if (MICROMIPS_P (dynobj)) + /* Multiply by compression ratio for micromips. */ + htab->iplt_entry_size = 4 + * (ARRAY_SIZE (micromips32_exec_iplt_entry) * 3 / 4); + else + htab->iplt_entry_size = 4 * (ARRAY_SIZE (mips32_exec_iplt_entry) + + (LOAD_INTERLOCKS_P (dynobj)? 0 : 1)); + } + + BFD_ASSERT (htab->root.igotplt == NULL); + + s = bfd_make_section_anyway_with_flags (dynobj, ".igot", flags); + if (s == NULL + || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) + return FALSE; + htab->root.igotplt = s; + mips_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE; + + BFD_ASSERT (htab->root.irelplt == NULL); + + s = bfd_make_section_with_flags (dynobj, ".rel.iplt", flags | SEC_READONLY); + if (s == NULL + || !bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) + return FALSE; + + htab->root.irelplt = s; + return TRUE; +} + /* Create the .got section to hold the global offset table. */ static bfd_boolean @@ -5203,6 +5540,74 @@ mips_elf_relocation_needs_la25_stub (bfd *input_bfd, int r_type, return FALSE; } } + +/* Find and/or create a hash entry for local symbol. */ + +static struct mips_elf_link_hash_entry * +get_local_sym_hash (struct mips_elf_link_hash_table *htab, + bfd *abfd, const Elf_Internal_Rela *rel) +{ + struct mips_elf_link_hash_entry e, *ret; + asection *sec; + hashval_t h; + void **slot; + Elf_Internal_Sym *isym; + Elf_Internal_Shdr *symtab_hdr; + char *namep; + + sec = bfd_get_section_by_name (abfd, ".text"); + h = ELF_LOCAL_SYMBOL_HASH (sec->id, ELF_R_SYM (abfd, rel->r_info)); + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, + ELF_R_SYM (abfd, rel->r_info)); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + namep = bfd_elf_string_from_elf_section (abfd, symtab_hdr->sh_link, + isym->st_name); + + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + elf_tdata (abfd)->has_gnu_symbols = TRUE; + + e.root.indx = sec->id; + e.root.dynstr_index = ELF_R_SYM (abfd, rel->r_info); + e.root.root.root.string = namep; + + slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, INSERT); + if (!slot) + return NULL; + + /* Found match */ + if (*slot) + { + ret = (struct mips_elf_link_hash_entry *) *slot; + return ret; + } + + /* Allocate new slot */ + ret = (struct mips_elf_link_hash_entry *) + objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, + sizeof (struct mips_elf_link_hash_entry)); + + if (ret) + { + memset (ret, 0, sizeof (*ret)); + ret->root.indx = sec->id; + ret->root.dynstr_index = ELF_R_SYM (abfd, rel->r_info); + ret->root.dynindx = -1; + ret->root.root.root.string = namep; + ret->root.root.u.def.section = sec; + ret->root.root.u.def.value = isym->st_value; + ret->root.got.offset = (bfd_vma) -1; + ret->global_got_area = GGA_NONE; + ret->root.type = STT_GNU_IFUNC; + ret->root.def_regular = 1; + ret->root.ref_regular = 1; + ret->root.forced_local = 1; + ret->root.root.type = bfd_link_hash_defined; + + *slot = ret; + } + + return ret; +} ? /* Calculate the value produced by the RELOCATION (which comes from the INPUT_BFD). The ADDEND is the addend to use for this @@ -5253,6 +5658,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, /* TRUE if the symbol referred to by this relocation is a local symbol. */ bfd_boolean local_p, was_local_p; + /* TRUE if the symbol referred to by this relocation is a local IFUNC */ + bfd_boolean local_gnu_ifunc_p = FALSE; /* TRUE if the symbol referred to by this relocation is "_gp_disp". */ bfd_boolean gp_disp_p = FALSE; /* TRUE if the symbol referred to by this relocation is @@ -5333,6 +5740,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other); target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other); + + if (sym->st_info == STT_GNU_IFUNC) + { + h = get_local_sym_hash (mips_elf_hash_table (info), input_bfd, + relocation); + local_gnu_ifunc_p = TRUE; + } } else { @@ -5557,6 +5971,17 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, target_is_16_bit_code_p = !micromips_p; target_is_micromips_code_p = micromips_p; } + /* If this symbol is an ifunc, point to the iplt stub for it. */ + else if (h && h->needs_iplt) + { + BFD_ASSERT (htab->root.iplt != NULL); + symbol = (htab->root.iplt->output_section->vma + + htab->root.iplt->output_offset + + h->iplt_offset); + /* Set ISA bit in address for compressed code. */ + if (ELF_ST_IS_COMPRESSED (h->root.other)) + symbol |= 1; + } /* Make sure MIPS16 and microMIPS are not used together. */ if ((r_type == R_MIPS16_26 && target_is_micromips_code_p) @@ -5941,10 +6366,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MICROMIPS_CALL16: /* VxWorks does not have separate local and global semantics for R_MIPS*_GOT16; every relocation evaluates to "G". */ + /* Local IFUNC symbols must be accessed through GOT, similar to global + symbols, to allow for indirection */ if (!htab->is_vxworks && local_p) { value = mips_elf_got16_entry (abfd, input_bfd, info, - symbol + addend, !was_local_p); + symbol + addend, + !was_local_p || local_gnu_ifunc_p, h); if (value == MINUS_ONE) return bfd_reloc_outofrange; value @@ -6448,31 +6876,41 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, if (defined_p && r_type != R_MIPS_REL32) *addendp += symbol; - if (htab->is_vxworks) - /* VxWorks uses non-relative relocations for this. */ - outrel[0].r_info = ELF32_R_INFO (indx, R_MIPS_32); + if (h && !indx && h->root.type == STT_GNU_IFUNC) + { + outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, + R_MIPS_IRELATIVE); + outrel[1].r_info = ELF_R_INFO (output_bfd, 0, + R_MIPS_NONE); + } else - /* The relocation is always an REL32 relocation because we don't - know where the shared library will wind up at load-time. */ - outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, - R_MIPS_REL32); - - /* For strict adherence to the ABI specification, we should - generate a R_MIPS_64 relocation record by itself before the - _REL32/_64 record as well, such that the addend is read in as - a 64-bit value (REL32 is a 32-bit relocation, after all). - However, since none of the existing ELF64 MIPS dynamic - loaders seems to care, we don't waste space with these - artificial relocations. If this turns out to not be true, - mips_elf_allocate_dynamic_relocation() should be tweaked so - as to make room for a pair of dynamic relocations per - invocation if ABI_64_P, and here we should generate an - additional relocation record with R_MIPS_64 by itself for a - NULL symbol before this relocation record. */ - outrel[1].r_info = ELF_R_INFO (output_bfd, 0, - ABI_64_P (output_bfd) - ? R_MIPS_64 - : R_MIPS_NONE); + { + if (htab->is_vxworks) + /* VxWorks uses non-relative relocations for this. */ + outrel[0].r_info = ELF32_R_INFO (indx, R_MIPS_32); + else + /* The relocation is always an REL32 relocation because we don't + know where the shared library will wind up at load-time. */ + outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, + R_MIPS_REL32); + + /* For strict adherence to the ABI specification, we should + generate a R_MIPS_64 relocation record by itself before the + _REL32/_64 record as well, such that the addend is read in as + a 64-bit value (REL32 is a 32-bit relocation, after all). + However, since none of the existing ELF64 MIPS dynamic + loaders seems to care, we don't waste space with these + artificial relocations. If this turns out to not be true, + mips_elf_allocate_dynamic_relocation() should be tweaked so + as to make room for a pair of dynamic relocations per + invocation if ABI_64_P, and here we should generate an + additional relocation record with R_MIPS_64 by itself for a + NULL symbol before this relocation record. */ + outrel[1].r_info = ELF_R_INFO (output_bfd, 0, + ABI_64_P (output_bfd) + ? R_MIPS_64 + : R_MIPS_NONE); + } outrel[2].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_NONE); /* Adjust the output offset of the relocation to reference the @@ -7019,6 +7457,8 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) hdr->sh_size += hdr->sh_addralign - adjust; } } + else if (strcmp (name, ".igot") == 0) + hdr->sh_entsize = MIPS_ELF_GOT_SIZE (abfd); } return TRUE; @@ -7381,6 +7821,9 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, flagword *flagsp ATTRIBUTE_UNUSED, asection **secp, bfd_vma *valp) { + if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE; + if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0 && strcmp (*namep, "_rld_new_interface") == 0) @@ -7932,6 +8375,13 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, bed = get_elf_backend_data (abfd); rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel; + /* This needs to happen early. If the sections aren't needed + they will not get generated. */ + if (htab->root.dynobj == NULL) + htab->root.dynobj = abfd; + if (!htab->root.iplt && !mips_elf_create_ifunc_sections (info)) + return FALSE; + /* Check for the mips16 stub sections. */ name = bfd_get_section_name (abfd, sec); @@ -8193,12 +8643,30 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, bfd_boolean can_make_dynamic_p; bfd_boolean call_reloc_p; bfd_boolean constrain_symbol_p; + bfd_boolean local_gnu_ifunc_p = FALSE; r_symndx = ELF_R_SYM (abfd, rel->r_info); r_type = ELF_R_TYPE (abfd, rel->r_info); if (r_symndx < extsymoff) - h = NULL; + { + Elf_Internal_Sym *isym; + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); + + if (isym == NULL) + return FALSE; + + /* Relocation is for local STT_GNU_IFUNC symbol. */ + if (isym->st_info == STT_GNU_IFUNC) + { + /* Ensure that we have a hash entry for this symbol. */ + if (get_local_sym_hash (htab, abfd, rel) == NULL) + return FALSE; + local_gnu_ifunc_p = TRUE; + } + + h = NULL; + } else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) { (*_bfd_error_handler) @@ -8410,7 +8878,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_CALL16: case R_MIPS16_CALL16: case R_MICROMIPS_CALL16: - if (h == NULL) + /* Exclude local IFUNCs from check */ + if (h == NULL && !local_gnu_ifunc_p) { (*_bfd_error_handler) (_("%B: CALL16 reloc at 0x%lx not against global symbol"), @@ -8435,9 +8904,11 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* We need a stub, not a plt entry for the undefined function. But we record it as if it needs plt. See - _bfd_elf_adjust_dynamic_symbol. */ + _bfd_elf_adjust_dynamic_symbol. If it is an ifunc + symbol it will go into an iplt section and not plt. */ h->needs_plt = 1; - h->type = STT_FUNC; + if (h->type != STT_GNU_IFUNC) + h->type = STT_FUNC; } break; @@ -8976,6 +9447,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, /* Make sure we know what is going on here. */ BFD_ASSERT (dynobj != NULL && (h->needs_plt + || h->type == STT_GNU_IFUNC || h->u.weakdef != NULL || (h->def_dynamic && h->ref_regular @@ -9254,6 +9726,11 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd, hti.error = FALSE; mips_elf_link_hash_traverse (mips_elf_hash_table (info), mips_elf_check_symbols, &hti); + + /* Allocate relocs for local IFUNC symbols. */ + htab_traverse (htab->loc_hash_table, + mips_elf_check_local_symbols, &hti); + if (hti.error) return FALSE; @@ -9298,9 +9775,17 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) count the number of reloc-only GOT symbols. */ mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info); + /* Count local IFUNC symbols. These need general GOT entries that + are fixed-up by explicit IRELATIVE relocations. */ + htab_traverse (htab->loc_hash_table, mips_elf_count_general_got_symbols, info); + if (!mips_elf_resolve_final_got_entries (info, g)) return FALSE; + g->assigned_general_gotno = htab->reserved_gotno; + g->local_gotno += g->general_gotno; + g->assigned_low_gotno += g->general_gotno; + /* Calculate the total loadable size of the output. That will give us the maximum number of GOT_PAGE entries required. */ @@ -9742,6 +10227,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, else if (! CONST_STRNEQ (name, ".init") && s != htab->sgot && s != htab->sgotplt + && s != htab->root.iplt + && s != htab->root.igotplt && s != htab->sstubs && s != htab->sdynbss) { @@ -9887,6 +10374,13 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0)) return FALSE; } + + if (htab->got_info->general_gotno > 0) + { + if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GENERAL_GOTNO, 0)) + return FALSE; + } + if (htab->is_vxworks && !elf_vxworks_add_dynamic_entries (output_bfd, info)) return FALSE; @@ -10018,6 +10512,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry *h; bfd_boolean rel_reloc; + bfd_boolean local_gnu_ifunc_p = FALSE; rel_reloc = (NEWABI_P (input_bfd) && mips_elf_rel_relocation_p (input_bfd, input_section, @@ -10031,6 +10526,23 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { sec = local_sections[r_symndx]; h = NULL; + + Elf_Internal_Sym *isym; + struct mips_elf_link_hash_table *htab; + htab = mips_elf_hash_table (info); + isym = bfd_sym_from_r_symndx (&htab->sym_cache, input_bfd, r_symndx); + + if (isym == NULL) + return FALSE; + + /* Relocation is for local STT_GNU_IFUNC symbol. */ + if (isym->st_info == STT_GNU_IFUNC) + { + /* Ensure that we have a hash entry for this symbol. */ + if (get_local_sym_hash (htab, input_bfd, rel) == NULL) + return FALSE; + local_gnu_ifunc_p = TRUE; + } } else { @@ -10091,8 +10603,9 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, && mips_elf_local_relocation_p (input_bfd, rel, local_sections))) { - if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend, - contents, &addend)) + if (!local_gnu_ifunc_p + && !mips_elf_add_lo16_rel_addend (input_bfd, rel, relend, + contents, &addend)) { if (h) name = h->root.root.string; @@ -10479,6 +10992,237 @@ mips_elf_irix6_finish_dynamic_symbol (bfd *abfd ATTRIBUTE_UNUSED, } } +/* Create the contents of the iplt entry for an IFUNC symbol. */ + +static bfd_boolean +mips_elf_create_iplt (bfd *output_bfd, + struct mips_elf_link_hash_table *htab, + struct mips_elf_link_hash_entry *hmips, + bfd_vma igotplt_address) +{ + bfd_byte *loc; + const bfd_vma *iplt_entry; + bfd_vma high = mips_elf_high (igotplt_address); + bfd_vma low = igotplt_address & 0xffff; + + /* Find out where the .iplt entry should go. */ + if (!htab->root.iplt->contents) + { + htab->root.iplt->contents = bfd_zalloc (output_bfd, + htab->root.iplt->size); + if (!htab->root.iplt->contents) + return FALSE; + } + loc = htab->root.iplt->contents + hmips->iplt_offset; + + /* Fill in the IPLT entry itself. */ + if (ABI_64_P (output_bfd)) + { + bfd_vma highest = mips_elf_highest (igotplt_address); + bfd_vma higher = mips_elf_higher (igotplt_address); + iplt_entry = mips64_exec_iplt_entry; + + if (highest) + { + /* Full 64-bit address space */ + bfd_put_32 (output_bfd, iplt_entry[0] | highest, loc); + bfd_put_32 (output_bfd, iplt_entry[1] | high, loc + 4); + bfd_put_32 (output_bfd, iplt_entry[2] | higher, loc + 8); + bfd_put_32 (output_bfd, iplt_entry[3], loc + 12); + bfd_put_32 (output_bfd, iplt_entry[4], loc + 16); + bfd_put_32 (output_bfd, iplt_entry[5] | low, loc + 20); + bfd_put_32 (output_bfd, iplt_entry[6], loc + 24); + bfd_put_32 (output_bfd, iplt_entry[7], loc + 28); + } + else if (higher) + { + /* 48-bit address space */ + iplt_entry = mips64_48b_exec_iplt_entry; + bfd_put_32 (output_bfd, iplt_entry[0] | higher, loc); + bfd_put_32 (output_bfd, iplt_entry[1] | high, loc + 4); + bfd_put_32 (output_bfd, iplt_entry[2], loc + 8); + bfd_put_32 (output_bfd, iplt_entry[3] | low, loc + 12); + bfd_put_32 (output_bfd, iplt_entry[4], loc + 16); + bfd_put_32 (output_bfd, iplt_entry[5], loc + 20); + } + else + { + /* 32-bit address space */ + bfd_put_32 (output_bfd, iplt_entry[0] | high, loc); + bfd_put_32 (output_bfd, iplt_entry[5] | low, loc + 4); + bfd_put_32 (output_bfd, iplt_entry[6], loc + 8); + bfd_put_32 (output_bfd, iplt_entry[7], loc + 12); + } + } + else if (ELF_ST_IS_MIPS16 (hmips->root.other)) + { + iplt_entry = mips16_exec_iplt_entry; + bfd_put_16 (output_bfd, iplt_entry[0], loc); + bfd_put_16 (output_bfd, iplt_entry[1], loc + 2); + bfd_put_16 (output_bfd, iplt_entry[2], loc + 4); + bfd_put_16 (output_bfd, iplt_entry[3], loc + 6); + bfd_put_32 (output_bfd, igotplt_address, loc + 8); + } + else if (ELF_ST_IS_MICROMIPS (hmips->root.other)) + { + iplt_entry = micromips32_exec_iplt_entry; + bfd_put_micromips_32 (output_bfd, iplt_entry[0] | high, loc); + bfd_put_micromips_32 (output_bfd, iplt_entry[1] | low , loc + 4); + + bfd_put_16 (output_bfd, iplt_entry[2], loc + 8); + bfd_put_16 (output_bfd, iplt_entry[3], loc + 10); + } + else + { + if (MIPSR6_P(output_bfd)) + iplt_entry = mips32r6_exec_iplt_entry; + else + iplt_entry = mips32_exec_iplt_entry; + bfd_put_32 (output_bfd, iplt_entry[0] | high, loc); + bfd_put_32 (output_bfd, iplt_entry[1] | low, loc + 4); + if (LOAD_INTERLOCKS_P (output_bfd)) + { + bfd_put_32 (output_bfd, iplt_entry[2], loc + 8); + bfd_put_32 (output_bfd, iplt_entry[3], loc + 12); + } + else + { + bfd_put_32 (output_bfd, iplt_entry[3], loc + 8); + bfd_put_32 (output_bfd, iplt_entry[2], loc + 12); + bfd_put_32 (output_bfd, iplt_entry[3], loc + 16); + } + } + + return TRUE; +} + +/* Find local GOT index for VALUE. Return -1 if no GOT slot is found. */ + +static bfd_vma +mips_elf_check_local_got_index (bfd *abfd, struct bfd_link_info *info, + bfd_vma value) +{ + struct mips_got_entry lookup, *entry; + void **loc; + struct mips_got_info *g; + struct mips_elf_link_hash_table *htab; + + htab = mips_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + g = mips_elf_bfd_got (abfd, FALSE); + BFD_ASSERT (g != NULL); + + lookup.abfd = NULL; + lookup.symndx = -1; + lookup.d.address = value; + lookup.tls_type = GOT_TLS_NONE; + loc = htab_find_slot (g->got_entries, &lookup, NO_INSERT); + if (!loc) + return -1; + + entry = (struct mips_got_entry *) *loc; + if (entry) + return entry->gotidx; + else + return -1; +} + +/* Create the IRELATIVE relocation for an IFUNC symbol. */ + +static bfd_boolean +mips_elf_create_ireloc (bfd *output_bfd, + bfd *dynobj, + struct mips_elf_link_hash_table *htab, + struct mips_elf_link_hash_entry *hmips, + Elf_Internal_Sym *sym, + struct bfd_link_info *info) +{ + bfd_vma igotplt_address = 0; + int igot_offset = -1; + asection *gotsect, *relsect; + + if (!hmips->needs_iplt) + { + gotsect = htab->sgot; + if (hmips->global_got_area == GGA_NORMAL) + igot_offset = mips_elf_primary_global_got_index (output_bfd, + info, &hmips->root); + else if (hmips->global_got_area == GGA_NONE) + igot_offset = mips_elf_check_local_got_index (output_bfd, info, + sym->st_value); + } + else + { + bfd_byte *loc; + bfd_vma igot_index; + gotsect = htab->root.igotplt; + igot_offset = hmips->igot_offset; + + /* Calculate the address of the IGOT entry. */ + igot_index = igot_offset / MIPS_ELF_GOT_SIZE (dynobj); + + if (!gotsect->contents) + { + gotsect->contents = bfd_zalloc (output_bfd, gotsect->size); + if (!gotsect->contents) + return FALSE; + } + + /* Initially point the .igot entry at the IFUNC resolver routine. */ + loc = (bfd_byte *) gotsect->contents + + igot_index * MIPS_ELF_GOT_SIZE (dynobj); + + if (ABI_64_P (output_bfd)) + bfd_put_64 (output_bfd, sym->st_value, loc); + else + bfd_put_32 (output_bfd, sym->st_value, loc); + } + + igotplt_address = (gotsect->output_section->vma + gotsect->output_offset + + igot_offset); + + relsect = mips_get_irel_section (info, htab); + + if (igot_offset >= 0) + { + if (hmips->needs_iplt && relsect->contents == NULL) + { + /* Allocate memory for the relocation section contents. */ + relsect->contents = bfd_zalloc (dynobj, relsect->size); + if (relsect->contents == NULL) + return FALSE; + } + + if (hmips->needs_iplt || hmips->global_got_area == GGA_NONE) + /* Emit an R_MIPS_IRELATIVE relocation against the [I]GOT entry. */ + mips_elf_output_dynamic_relocation (output_bfd, relsect, + relsect->reloc_count++, 0, + R_MIPS_IRELATIVE, igotplt_address); + else if (hmips->global_got_area == GGA_NORMAL) + { + /* Emit an R_MIPS_REL32 relocation against global GOT entry for + a preemptible symbol. */ + asection *sec = hmips->root.root.u.def.section; + Elf_Internal_Rela rel[3]; + + memset (rel, 0, sizeof (rel)); + rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_REL32); + rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = igot_offset; + + mips_elf_create_dynamic_relocation (output_bfd, info, rel, hmips, + sec, sym->st_value, NULL, + gotsect); + } + } + /* If necessary, generate the corresponding .iplt entry. */ + if (hmips->needs_iplt + && !mips_elf_create_iplt (output_bfd, htab, hmips, igotplt_address)) + return FALSE; + + return TRUE; +} + /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ @@ -10807,6 +11551,19 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, sym->st_other = other; } + if (hmips->root.type == STT_GNU_IFUNC) + { + if (hmips->needs_ireloc + && !mips_elf_create_ireloc (output_bfd, dynobj, htab, + hmips, sym, info)) + return FALSE; + + if (!elf_hash_table (info)->dynamic_sections_created) + return TRUE; + if (h->dynindx == -1 && !h->forced_local) + return TRUE; + } + /* If we have a MIPS16 function with a stub, the dynamic symbol must refer to the stub, since only the stub uses the standard calling conventions. */ @@ -10970,9 +11727,37 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, sym->st_other -= STO_MICROMIPS; } + if (hmips->needs_iplt) + { + /* Point at the iplt stub for this ifunc symbol. */ + sym->st_value = htab->root.iplt->output_section->vma + + htab->root.iplt->output_offset + hmips->iplt_offset; + sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_FUNC); + if (ELF_ST_IS_COMPRESSED (hmips->root.other)) + sym->st_value |= 1; + } + return TRUE; } +/* Finish up local dynamic symbol handling. We set the contents of + various dynamic sections here. */ + +static bfd_boolean +_bfd_mips_elf_finish_local_dynamic_symbol (void **slot, void *inf) +{ + struct mips_elf_link_hash_entry *h = (struct mips_elf_link_hash_entry *) *slot; + struct bfd_link_info *info = (struct bfd_link_info *)inf; + Elf_Internal_Sym isym; + + isym.st_value = h->root.root.u.def.section->output_section->vma + + h->root.root.u.def.section->output_offset + h->root.root.u.def.value; + isym.st_other = h->root.other; + + return _bfd_mips_elf_finish_dynamic_symbol (info->output_bfd, info, + &h->root, &isym); +} + /* Likewise, for VxWorks. */ bfd_boolean @@ -11358,6 +12143,13 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, sgot = htab->sgot; gg = htab->got_info; + if (htab_elements (htab->loc_hash_table) > 0) + { + /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ + htab_traverse (htab->loc_hash_table, + _bfd_mips_elf_finish_local_dynamic_symbol, info); + } + if (elf_hash_table (info)->dynamic_sections_created) { bfd_byte *b; @@ -11528,6 +12320,10 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = s->vma; break; + case DT_MIPS_GENERAL_GOTNO: + dyn.d_un.d_val = htab->reserved_gotno + gg->general_gotno; + break; + case DT_RELASZ: BFD_ASSERT (htab->is_vxworks); /* The count does not include the JUMP_SLOT relocations. */ @@ -13862,6 +14658,48 @@ _bfd_mips_elf_relax_section (bfd *abfd, asection *sec, return FALSE; } ? +/* Compute a hash of a local hash entry. We use elf_link_hash_entry + for local symbol so that we can handle local STT_GNU_IFUNC symbols + as global symbol. We reuse indx and dynstr_index for local symbol + hash since they aren't used by global symbols in this backend. */ + +static hashval_t +local_htab_hash (const void *ptr) +{ + struct mips_elf_link_hash_entry *h = + (struct mips_elf_link_hash_entry *) ptr; + return ELF_LOCAL_SYMBOL_HASH (h->root.indx, h->root.dynstr_index); +} + +/* Compare local hash entries. */ + +static int +local_htab_eq (const void *ptr1, const void *ptr2) +{ + struct mips_elf_link_hash_entry *h1 = + (struct mips_elf_link_hash_entry *) ptr1; + struct mips_elf_link_hash_entry *h2 = + (struct mips_elf_link_hash_entry *) ptr2; + + return h1->root.indx == h2->root.indx && + h1->root.dynstr_index == h2->root.dynstr_index; +} + +/* Destroy a MIPS ELF linker hash table. */ + +static void +_bfd_mips_elf_link_hash_table_free (bfd *obfd) +{ + struct mips_elf_link_hash_table *htab; + + htab = (struct mips_elf_link_hash_table *) obfd->link.hash; + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create a MIPS ELF linker hash table. */ struct bfd_link_hash_table * @@ -13885,6 +14723,17 @@ _bfd_mips_elf_link_hash_table_create (bfd *abfd) ret->root.init_plt_refcount.plist = NULL; ret->root.init_plt_offset.plist = NULL; + /* Create hash table for local IFUNC symbols. */ + ret->loc_hash_table = htab_try_create (1024, + local_htab_hash, + local_htab_eq, + NULL); + ret->loc_hash_memory = objalloc_create (); + if (!ret->loc_hash_table || !ret->loc_hash_memory) + { + _bfd_mips_elf_link_hash_table_free (abfd); + return NULL; + } return &ret->root.root; } @@ -15509,7 +16358,9 @@ _bfd_mips_elf_get_target_dtag (bfd_vma dtag) return "DT_MIPS_PLTGOT"; case DT_MIPS_RWPLT: return "DT_MIPS_RWPLT"; - } + case DT_MIPS_GENERAL_GOTNO: + return "DT_MIPS_GENERAL_GOTNO"; + } } /* Return the meaning of Tag_GNU_MIPS_ABI_FP value FP, or null if diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 18e3c40..2d0742d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1199,6 +1199,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MIPS_COPY", "BFD_RELOC_MIPS_JUMP_SLOT", + "BFD_RELOC_MIPS_IRELATIVE", "BFD_RELOC_MOXIE_10_PCREL", "BFD_RELOC_FT32_10", diff --git a/bfd/reloc.c b/bfd/reloc.c index 3478006..18ed890 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2450,6 +2450,11 @@ ENUMDOC COMMENT ENUM + BFD_RELOC_MIPS_IRELATIVE +ENUMDOC + MIPS support for STT_GNU_IFUNC. + +ENUM BFD_RELOC_MOXIE_10_PCREL ENUMDOC Moxie ELF relocations. diff --git a/binutils/readelf.c b/binutils/readelf.c index c313db4..7f97758 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1724,6 +1724,8 @@ 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_GENERAL_GOTNO: return "MIPS_GENERAL_GOTNO"; + default: return NULL; } @@ -8514,6 +8516,7 @@ dynamic_section_mips_val (Elf_Internal_Dyn * entry) case DT_MIPS_DELTA_SYM_NO: case DT_MIPS_DELTA_CLASSSYM_NO: case DT_MIPS_COMPACT_SIZE: + case DT_MIPS_GENERAL_GOTNO: print_vma (entry->d_un.d_ptr, DEC); break; diff --git a/elfcpp/elfcpp.h b/elfcpp/elfcpp.h index 722984e..f919fb8 100644 --- a/elfcpp/elfcpp.h +++ b/elfcpp/elfcpp.h @@ -866,6 +866,8 @@ enum DT DT_MIPS_PLTGOT = 0x70000032, // Points to the base of a writable PLT. DT_MIPS_RWPLT = 0x70000034, + // The GOT index of the first implicitly relocated GOT entry. + DT_MIPS_GENERAL_GOTNO = 0x70000036, DT_AUXILIARY = 0x7ffffffd, DT_USED = 0x7ffffffe, diff --git a/include/elf/mips.h b/include/elf/mips.h index 57de3bc..4005047 100644 --- a/include/elf/mips.h +++ b/include/elf/mips.h @@ -115,6 +115,9 @@ START_RELOC_NUMBERS (elf_mips_reloc_type) RELOC_NUMBER (R_MIPS_COPY, 126) RELOC_NUMBER (R_MIPS_JUMP_SLOT, 127) + /* STT_GNU_IFUNC support */ + RELOC_NUMBER (R_MIPS_IRELATIVE, 128) + /* These relocations are specific to microMIPS. */ FAKE_RELOC (R_MICROMIPS_min, 130) RELOC_NUMBER (R_MICROMIPS_26_S1, 133) @@ -751,6 +754,10 @@ 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 + +/* The GOT index of the first implicitly relocated GOT entry. */ +#define DT_MIPS_GENERAL_GOTNO 0x70000036 + ? /* Flags which may appear in a DT_MIPS_FLAGS entry. */ -- 1.7.9.5
Attachment:
Spec.txt
Description: Spec.txt
From a2c0aab6fb7bb35134a7d404add3301cc99569d0 Mon Sep 17 00:00:00 2001 From: Faraz Shahbazker <faraz.shahbazker@imgtec.com> Date: Tue, 21 Jul 2015 04:15:25 -0700 Subject: [PATCH 2/2] [RFC] Add IFUNC tests for MIPS ld/testsuite/ChangeLog: * ld-mips-elf/mips-ifunc.exp: Ifunc test script * ifunc-3-n32.r, ifunc-3-n32.sym, ifunc-3-n32.t, ifunc-3-n64.r, ifunc-3-n64.sym, ifunc-3-n64.t, ifunc-3-o32.r, ifunc-3-o32.sym, ifunc-3-o32.t, ifunc-4-n32.r, ifunc-4-n32.sym, ifunc-4-n32.t, ifunc-4-n64.r, ifunc-4-n64.sym, ifunc-4-n64.t, ifunc-4-o32.r, ifunc-4-o32.sym, ifunc-4-o32.t, ifunc-5-n32.g, ifunc-5-n32.r, ifunc-5-n32.sym, ifunc-5-n64.g, ifunc-5-n64.r, ifunc-5-n64.sym, ifunc-5-o32.g, ifunc-5-o32.r, ifunc-5-o32.sym, ifunc-6-n32.r, ifunc-6-n32.sym, ifunc-6-n64.r, ifunc-6-n64.sym, ifunc-6-o32.r, ifunc-6-o32.sym, ifunc-dyn-def.s, ifunc-dyn-main.s, ifunc-dyn-ref.s, ifunc-dyn.ld, ifunc-iplt.ld, ifunc-iplt-0x400000.t, ifunc-iplt-0x400000000.t, ifunc-iplt-0x4000000000000.t, ifunc-static-def.s, ifunc-static-main.s, ifunc-static-ref.s, ifunc-static.ld, libifunc-1-n32.sym, libifunc-1-n64.sym, libifunc-1-o32.sym, libifunc-2-n32.sym, libifunc-2-n64.sym, libifunc-2-o32.sym: New tests. --- ld/testsuite/ld-mips-elf/ifunc-3-n32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-3-n32.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-3-n32.t | 10 ++ ld/testsuite/ld-mips-elf/ifunc-3-n64.r | 8 + ld/testsuite/ld-mips-elf/ifunc-3-n64.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-3-n64.t | 11 ++ ld/testsuite/ld-mips-elf/ifunc-3-o32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-3-o32.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-3-o32.t | 11 ++ ld/testsuite/ld-mips-elf/ifunc-4-n32.r | 3 + ld/testsuite/ld-mips-elf/ifunc-4-n32.sym | 29 ++++ ld/testsuite/ld-mips-elf/ifunc-4-n32.t | 10 ++ ld/testsuite/ld-mips-elf/ifunc-4-n64.r | 5 + ld/testsuite/ld-mips-elf/ifunc-4-n64.sym | 29 ++++ ld/testsuite/ld-mips-elf/ifunc-4-n64.t | 11 ++ ld/testsuite/ld-mips-elf/ifunc-4-o32.r | 3 + ld/testsuite/ld-mips-elf/ifunc-4-o32.sym | 24 +++ ld/testsuite/ld-mips-elf/ifunc-4-o32.t | 11 ++ ld/testsuite/ld-mips-elf/ifunc-5-n32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-5-n32.sym | 5 + ld/testsuite/ld-mips-elf/ifunc-5-n64.r | 8 + ld/testsuite/ld-mips-elf/ifunc-5-n64.sym | 5 + ld/testsuite/ld-mips-elf/ifunc-5-o32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-5-o32.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-6-n32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-6-n32.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-6-n64.r | 8 + ld/testsuite/ld-mips-elf/ifunc-6-n64.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-6-o32.r | 4 + ld/testsuite/ld-mips-elf/ifunc-6-o32.sym | 6 + ld/testsuite/ld-mips-elf/ifunc-dyn-def.s | 67 +++++++++ ld/testsuite/ld-mips-elf/ifunc-dyn-main.s | 39 +++++ ld/testsuite/ld-mips-elf/ifunc-dyn-ref.s | 43 ++++++ ld/testsuite/ld-mips-elf/ifunc-dyn.ld | 25 ++++ ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000.t | 11 ++ ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000000.t | 13 ++ .../ld-mips-elf/ifunc-iplt-0x4000000000000.t | 14 ++ ld/testsuite/ld-mips-elf/ifunc-iplt.ld | 26 ++++ ld/testsuite/ld-mips-elf/ifunc-static-def.s | 155 ++++++++++++++++++++ ld/testsuite/ld-mips-elf/ifunc-static-main.s | 39 +++++ ld/testsuite/ld-mips-elf/ifunc-static-ref.s | 39 +++++ ld/testsuite/ld-mips-elf/ifunc-static.ld | 27 ++++ ld/testsuite/ld-mips-elf/libifunc-1-n32.sym | 4 + ld/testsuite/ld-mips-elf/libifunc-1-n64.sym | 4 + ld/testsuite/ld-mips-elf/libifunc-1-o32.sym | 4 + ld/testsuite/ld-mips-elf/libifunc-2-n32.sym | 4 + ld/testsuite/ld-mips-elf/libifunc-2-n64.sym | 4 + ld/testsuite/ld-mips-elf/libifunc-2-o32.sym | 5 + ld/testsuite/ld-mips-elf/mips-ifunc.exp | 149 +++++++++++++++++++ 49 files changed, 929 insertions(+) create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n32.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n64.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-n64.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-o32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-3-o32.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n32.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n64.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-n64.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-o32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-4-o32.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-n32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-n64.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-o32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-5-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-n32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-n64.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-o32.r create mode 100644 ld/testsuite/ld-mips-elf/ifunc-6-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/ifunc-dyn-def.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-dyn-main.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-dyn-ref.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-dyn.ld create mode 100644 ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000000.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-iplt-0x4000000000000.t create mode 100644 ld/testsuite/ld-mips-elf/ifunc-iplt.ld create mode 100644 ld/testsuite/ld-mips-elf/ifunc-static-def.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-static-main.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-static-ref.s create mode 100644 ld/testsuite/ld-mips-elf/ifunc-static.ld create mode 100644 ld/testsuite/ld-mips-elf/libifunc-1-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/libifunc-1-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/libifunc-1-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/libifunc-2-n32.sym create mode 100644 ld/testsuite/ld-mips-elf/libifunc-2-n64.sym create mode 100644 ld/testsuite/ld-mips-elf/libifunc-2-o32.sym create mode 100644 ld/testsuite/ld-mips-elf/mips-ifunc.exp diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n32.r b/ld/testsuite/ld-mips-elf/ifunc-3-n32.r new file mode 100644 index 0000000..b14c140 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n32.sym b/ld/testsuite/ld-mips-elf/ifunc-3-n32.sym new file mode 100644 index 0000000..6068a87 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n32.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 00000000 0 FUNC GLOBAL DEFAULT UND ref1 + 2 0: 00000400 28 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 00000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 0000100c 0 OBJECT GLOBAL DEFAULT 14 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n32.t b/ld/testsuite/ld-mips-elf/ifunc-3-n32.t new file mode 100644 index 0000000..edf2787 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n32.t @@ -0,0 +1,10 @@ +tmpdir/ifunc-3-n32: file format elf32-ntradbigmips + + +Disassembly of section .iplt: + +00000400 <.iplt.func1>: + 400: 3c0f0000 lui t3,0x0 + 404: 8df90800 lw t9,2048\(t3\) + 408: 03200008 jr t9 + 40c: 00000000 nop diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n64.r b/ld/testsuite/ld-mips-elf/ifunc-3-n64.r new file mode 100644 index 0000000..53b6455 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n64.r @@ -0,0 +1,8 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym. Value Sym. Name +000000000000 000000000000 R_MIPS_NONE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE +000000000800 000000000080 R_MIPS_IRELATIVE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n64.sym b/ld/testsuite/ld-mips-elf/ifunc-3-n64.sym new file mode 100644 index 0000000..bc9c09f --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n64.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 0000000000000000 0 FUNC GLOBAL DEFAULT UND ref1 + 2 0: 0000000000000400 28 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 0000000000000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 0000000000001018 0 OBJECT GLOBAL DEFAULT 14 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-n64.t b/ld/testsuite/ld-mips-elf/ifunc-3-n64.t new file mode 100644 index 0000000..0df1db2 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-n64.t @@ -0,0 +1,11 @@ +tmpdir/ifunc-3-n64: file format elf64-tradbigmips + + +Disassembly of section .iplt: + +0000000000000400 <.iplt.func1>: + 400: 3c0f0000 lui t3,0x0 + 404: ddf90800 ld t9,2048\(t3\) + 408: 03200008 jr t9 + 40c: 00000000 nop + ... diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-o32.r b/ld/testsuite/ld-mips-elf/ifunc-3-o32.r new file mode 100644 index 0000000..b14c140 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-o32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-o32.sym b/ld/testsuite/ld-mips-elf/ifunc-3-o32.sym new file mode 100644 index 0000000..a6c92d1 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-o32.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 00000000 0 FUNC GLOBAL DEFAULT UND ref1 + 2 0: 00000400 40 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 00000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 0000100c 0 OBJECT GLOBAL DEFAULT 14 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-3-o32.t b/ld/testsuite/ld-mips-elf/ifunc-3-o32.t new file mode 100644 index 0000000..eba438f --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-3-o32.t @@ -0,0 +1,11 @@ +tmpdir/ifunc-3-o32: file format elf32-tradbigmips + + +Disassembly of section .iplt: + +00000400 <.iplt.func1>: + 400: 3c0f0000 lui t7,0x0 + 404: 8df90800 lw t9,2048\(t7\) + 408: 00000000 nop + 40c: 03200008 jr t9 + 410: 00000000 nop diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n32.r b/ld/testsuite/ld-mips-elf/ifunc-4-n32.r new file mode 100644 index 0000000..e899ffc --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n32.r @@ -0,0 +1,3 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 1 entries: + Offset Info Type Sym.Value Sym. Name +00080800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n32.sym b/ld/testsuite/ld-mips-elf/ifunc-4-n32.sym new file mode 100644 index 0000000..4761ae5 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n32.sym @@ -0,0 +1,29 @@ +Symbol table '.symtab' contains 27 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 00080000 0 SECTION LOCAL DEFAULT 1 + 2: 00080400 0 SECTION LOCAL DEFAULT 2 + 3: 00080800 0 SECTION LOCAL DEFAULT 3 + 4: 00081000 0 SECTION LOCAL DEFAULT 4 + 5: 00081008 0 SECTION LOCAL DEFAULT 5 + 6: 00081020 0 SECTION LOCAL DEFAULT 6 + 7: 00000000 0 SECTION LOCAL DEFAULT 7 + 8: 00000000 0 SECTION LOCAL DEFAULT 8 + 9: 00000000 0 SECTION LOCAL DEFAULT 9 + 10: 00000000 0 FILE LOCAL DEFAULT ABS ifunc_ref_main_1.c + 11: 00000000 0 FILE LOCAL DEFAULT ABS ifunc.c + 12: 00080430 36 FUNC LOCAL DEFAULT 2 f1_a + 13: 00080454 36 FUNC LOCAL DEFAULT 2 f1_b + 14: 00080478 36 FUNC LOCAL DEFAULT 2 f1_c + 15: 000804d0 0 NOTYPE LOCAL DEFAULT 2 \$L8 + 16: 000804d8 0 NOTYPE LOCAL DEFAULT 2 \$L9 + 17: 000804f8 0 NOTYPE LOCAL DEFAULT 2 \$L10 + 18: 00080520 0 NOTYPE LOCAL DEFAULT 2 \$L13 + 19: 00080518 0 NOTYPE LOCAL DEFAULT 2 \$L12 + 20: 00000000 0 FILE LOCAL DEFAULT ABS ifunc_ref.c + 21: 00000000 0 FILE LOCAL DEFAULT ABS + 22: 00080000 16 FUNC LOCAL DEFAULT 1 .iplt.func1 + 23: 0008049c 156 IFUNC GLOBAL DEFAULT 2 func1 + 24: 00080400 48 FUNC GLOBAL DEFAULT 2 main + 25: 00080540 48 FUNC GLOBAL DEFAULT 2 ref1 + 26: 0008049c 156 FUNC GLOBAL DEFAULT 2 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n32.t b/ld/testsuite/ld-mips-elf/ifunc-4-n32.t new file mode 100644 index 0000000..a681706 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n32.t @@ -0,0 +1,10 @@ +tmpdir/ifunc-4-n32: file format elf32-ntradbigmips + + +Disassembly of section .iplt: + +00080000 <.iplt.func1>: + 80000: 3c0f0008 lui t3,0x8 + 80004: 8df90800 lw t9,2048\(t3\) + 80008: 03200008 jr t9 + 8000c: 00000000 nop diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n64.r b/ld/testsuite/ld-mips-elf/ifunc-4-n64.r new file mode 100644 index 0000000..695742b --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n64.r @@ -0,0 +1,5 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 1 entries: + Offset Info Type Sym. Value Sym. Name +000000080800 000000000080 R_MIPS_IRELATIVE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n64.sym b/ld/testsuite/ld-mips-elf/ifunc-4-n64.sym new file mode 100644 index 0000000..0d044f5 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n64.sym @@ -0,0 +1,29 @@ +Symbol table '.symtab' contains 27 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 0000000000080000 0 SECTION LOCAL DEFAULT 1 + 2: 0000000000080400 0 SECTION LOCAL DEFAULT 2 + 3: 0000000000080800 0 SECTION LOCAL DEFAULT 3 + 4: 0000000000081000 0 SECTION LOCAL DEFAULT 4 + 5: 0000000000081010 0 SECTION LOCAL DEFAULT 5 + 6: 0000000000081088 0 SECTION LOCAL DEFAULT 6 + 7: 0000000000000000 0 SECTION LOCAL DEFAULT 7 + 8: 0000000000000000 0 SECTION LOCAL DEFAULT 8 + 9: 0000000000000000 0 SECTION LOCAL DEFAULT 9 + 10: 0000000000000000 0 FILE LOCAL DEFAULT ABS ifunc_ref_main_1.c + 11: 0000000000000000 0 FILE LOCAL DEFAULT ABS ifunc.c + 12: 0000000000080430 36 FUNC LOCAL DEFAULT 2 f1_a + 13: 0000000000080454 36 FUNC LOCAL DEFAULT 2 f1_b + 14: 0000000000080478 36 FUNC LOCAL DEFAULT 2 f1_c + 15: 00000000000804d0 0 NOTYPE LOCAL DEFAULT 2 \$L8 + 16: 00000000000804d8 0 NOTYPE LOCAL DEFAULT 2 \$L9 + 17: 00000000000804f8 0 NOTYPE LOCAL DEFAULT 2 \$L10 + 18: 0000000000080520 0 NOTYPE LOCAL DEFAULT 2 \$L13 + 19: 0000000000080518 0 NOTYPE LOCAL DEFAULT 2 \$L12 + 20: 0000000000000000 0 FILE LOCAL DEFAULT ABS ifunc_ref.c + 21: 0000000000000000 0 FILE LOCAL DEFAULT ABS + 22: 0000000000080000 32 FUNC LOCAL DEFAULT 1 .iplt.func1 + 23: 000000000008049c 156 IFUNC GLOBAL DEFAULT 2 func1 + 24: 0000000000080400 48 FUNC GLOBAL DEFAULT 2 main + 25: 0000000000080540 48 FUNC GLOBAL DEFAULT 2 ref1 + 26: 000000000008049c 156 FUNC GLOBAL DEFAULT 2 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-n64.t b/ld/testsuite/ld-mips-elf/ifunc-4-n64.t new file mode 100644 index 0000000..bf5a2d2 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-n64.t @@ -0,0 +1,11 @@ +tmpdir/ifunc-4-n64: file format elf64-tradbigmips + + +Disassembly of section .iplt: + +0000000000080000 <.iplt.func1>: + 80000: 3c0f0008 lui t3,0x8 + 80004: ddf90800 ld t9,2048\(t3\) + 80008: 03200008 jr t9 + 8000c: 00000000 nop + ... diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-o32.r b/ld/testsuite/ld-mips-elf/ifunc-4-o32.r new file mode 100644 index 0000000..e899ffc --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-o32.r @@ -0,0 +1,3 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 1 entries: + Offset Info Type Sym.Value Sym. Name +00080800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-o32.sym b/ld/testsuite/ld-mips-elf/ifunc-4-o32.sym new file mode 100644 index 0000000..4f6e13e --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-o32.sym @@ -0,0 +1,24 @@ +Symbol table '.symtab' contains 22 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 00000000 0 NOTYPE LOCAL DEFAULT UND + 1: 00080000 0 SECTION LOCAL DEFAULT 1 + 2: 00080400 0 SECTION LOCAL DEFAULT 2 + 3: 00080800 0 SECTION LOCAL DEFAULT 3 + 4: 00081000 0 SECTION LOCAL DEFAULT 4 + 5: 00081008 0 SECTION LOCAL DEFAULT 5 + 6: 00081020 0 SECTION LOCAL DEFAULT 6 + 7: 00000000 0 SECTION LOCAL DEFAULT 7 + 8: 00000000 0 SECTION LOCAL DEFAULT 8 + 9: 00000000 0 SECTION LOCAL DEFAULT 9 + 10: 00000000 0 FILE LOCAL DEFAULT ABS ifunc_ref_main_1.c + 11: 00000000 0 FILE LOCAL DEFAULT ABS ifunc.c + 12: 00080430 36 FUNC LOCAL DEFAULT 2 f1_a + 13: 00080454 36 FUNC LOCAL DEFAULT 2 f1_b + 14: 00080478 36 FUNC LOCAL DEFAULT 2 f1_c + 15: 00000000 0 FILE LOCAL DEFAULT ABS ifunc_ref.c + 16: 00000000 0 FILE LOCAL DEFAULT ABS + 17: 00080000 20 FUNC LOCAL DEFAULT 1 .iplt.func1 + 18: 0008049c 156 IFUNC GLOBAL DEFAULT 2 func1 + 19: 00080400 48 FUNC GLOBAL DEFAULT 2 main + 20: 00080540 48 FUNC GLOBAL DEFAULT 2 ref1 + 21: 0008049c 156 FUNC GLOBAL DEFAULT 2 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-4-o32.t b/ld/testsuite/ld-mips-elf/ifunc-4-o32.t new file mode 100644 index 0000000..bc71cb0 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-4-o32.t @@ -0,0 +1,11 @@ +tmpdir/ifunc-4-o32: file format elf32-tradbigmips + + +Disassembly of section .iplt: + +00080000 <.iplt.func1>: + 80000: 3c0f0008 lui t7,0x8 + 80004: 8df90800 lw t9,2048\(t7\) + 80008: 00000000 nop + 8000c: 03200008 jr t9 + 80010: 00000000 nop diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-n32.r b/ld/testsuite/ld-mips-elf/ifunc-5-n32.r new file mode 100644 index 0000000..fb0ef4a --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-n32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000410 00000403 R_MIPS_REL32 func1\(\) func1 diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-n32.sym b/ld/testsuite/ld-mips-elf/ifunc-5-n32.sym new file mode 100644 index 0000000..3756726 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-n32.sym @@ -0,0 +1,5 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 2 0: 00000030 60 FUNC GLOBAL DEFAULT 1 ref1 + 4 0: 0000000c 28 IFUNC GLOBAL DEFAULT 1 func1 + 3 1: 0000000c 28 FUNC GLOBAL DEFAULT 1 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-n64.r b/ld/testsuite/ld-mips-elf/ifunc-5-n64.r new file mode 100644 index 0000000..718d84a --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-n64.r @@ -0,0 +1,8 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 2 entries: + Offset Info Type Sym. Value Sym. Name +000000000000 000000000000 R_MIPS_NONE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE +000000000420 000400001203 R_MIPS_REL32 func1\(\) func1 + Type2: R_MIPS_64 + Type3: R_MIPS_NONE diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-n64.sym b/ld/testsuite/ld-mips-elf/ifunc-5-n64.sym new file mode 100644 index 0000000..c28e09a --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-n64.sym @@ -0,0 +1,5 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 2 0: 0000000000000030 60 FUNC GLOBAL DEFAULT 1 ref1 + 4 0: 000000000000000c 28 IFUNC GLOBAL DEFAULT 1 func1 + 3 1: 000000000000000c 28 FUNC GLOBAL DEFAULT 1 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-o32.r b/ld/testsuite/ld-mips-elf/ifunc-5-o32.r new file mode 100644 index 0000000..dbb3325 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-o32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x11000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000410 00000503 R_MIPS_REL32 func1\(\) func1 diff --git a/ld/testsuite/ld-mips-elf/ifunc-5-o32.sym b/ld/testsuite/ld-mips-elf/ifunc-5-o32.sym new file mode 100644 index 0000000..66a60f7 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-5-o32.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 3 0: 00000040 76 FUNC GLOBAL DEFAULT 1 ref1 + 5 0: 0000000c 40 IFUNC GLOBAL DEFAULT 1 func1 + 2 0: 00000000 0 SECTION GLOBAL DEFAULT ABS _gp_disp + 4 1: 0000000c 40 FUNC GLOBAL DEFAULT 1 func1_ifunc diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-n32.r b/ld/testsuite/ld-mips-elf/ifunc-6-n32.r new file mode 100644 index 0000000..b14c140 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-n32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-n32.sym b/ld/testsuite/ld-mips-elf/ifunc-6-n32.sym new file mode 100644 index 0000000..2c822d9 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-n32.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 00000070 60 FUNC GLOBAL DEFAULT 1 ref1 + 2 0: 00000400 28 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 00000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 00001000 0 OBJECT GLOBAL DEFAULT 12 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-n64.r b/ld/testsuite/ld-mips-elf/ifunc-6-n64.r new file mode 100644 index 0000000..53b6455 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-n64.r @@ -0,0 +1,8 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym. Value Sym. Name +000000000000 000000000000 R_MIPS_NONE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE +000000000800 000000000080 R_MIPS_IRELATIVE + Type2: R_MIPS_NONE + Type3: R_MIPS_NONE diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-n64.sym b/ld/testsuite/ld-mips-elf/ifunc-6-n64.sym new file mode 100644 index 0000000..500aada --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-n64.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 0000000000000070 60 FUNC GLOBAL DEFAULT 1 ref1 + 2 0: 0000000000000400 28 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 0000000000000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 0000000000001000 0 OBJECT GLOBAL DEFAULT 12 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-o32.r b/ld/testsuite/ld-mips-elf/ifunc-6-o32.r new file mode 100644 index 0000000..b14c140 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-o32.r @@ -0,0 +1,4 @@ +Relocation section '.rel.dyn' at offset 0x12000 contains 2 entries: + Offset Info Type Sym.Value Sym. Name +00000000 00000000 R_MIPS_NONE +00000800 00000080 R_MIPS_IRELATIVE diff --git a/ld/testsuite/ld-mips-elf/ifunc-6-o32.sym b/ld/testsuite/ld-mips-elf/ifunc-6-o32.sym new file mode 100644 index 0000000..a39cb03 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-6-o32.sym @@ -0,0 +1,6 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 4 0: 00000080 76 FUNC GLOBAL DEFAULT 1 ref1 + 2 0: 00000400 40 FUNC GLOBAL DEFAULT 1 func1 + 1 1: 00000001 0 SECTION GLOBAL DEFAULT ABS _DYNAMIC_LINKING + 3 2: 00001000 0 OBJECT GLOBAL DEFAULT 12 __RLD_MAP diff --git a/ld/testsuite/ld-mips-elf/ifunc-dyn-def.s b/ld/testsuite/ld-mips-elf/ifunc-dyn-def.s new file mode 100644 index 0000000..9b5d2a8 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-dyn-def.s @@ -0,0 +1,67 @@ + .file 1 "ifunc.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .text + .align 2 + .set nomips16 + .set nomicromips + .ent f1_a + .type f1_a, @function +f1_a: + nop + + .set macro + .set reorder + .end f1_a + .size f1_a, .-f1_a + .align 2 + .set nomips16 + .set nomicromips + .ent f1_b + .type f1_b, @function +f1_b: + nop + + .set macro + .set reorder + .end f1_b + .size f1_b, .-f1_b + .align 2 + .set nomips16 + .set nomicromips + .ent f1_c + .type f1_c, @function +f1_c: + .frame $fp,8,$31 # vars= 0, regs= 1/0, args= 0, gp= 0 + nop + + .set macro + .set reorder + .end f1_c + .size f1_c, .-f1_c + .align 2 + .globl func1_ifunc + .set nomips16 + .set nomicromips + .ent func1_ifunc + .type func1_ifunc, @function +func1_ifunc: + lw $2,%got(f1_a)($28) + addiu $2,$2,%lo(f1_a) + lw $2,%got(f1_b)($28) + addiu $2,$2,%lo(f1_b) + lw $2,%got(f1_c)($28) + addiu $2,$2,%lo(f1_c) + nop + + .set macro + .set reorder + .end func1_ifunc + .size func1_ifunc, .-func1_ifunc + .globl func1 + .type func1, @gnu_indirect_function + func1 = func1_ifunc + .ident "GCC: (GNU) 4.9.0 20130917 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-dyn-main.s b/ld/testsuite/ld-mips-elf/ifunc-dyn-main.s new file mode 100644 index 0000000..8c12176 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-dyn-main.s @@ -0,0 +1,39 @@ + .file 1 "ifunc_ref_main_2.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .option pic0 + .text + .align 2 + .globl main + .set nomips16 + .set nomicromips + .ent main + .type main, @function +main: + .frame $fp,32,$31 # vars= 0, regs= 2/0, args= 16, gp= 8 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-32 + sw $31,28($sp) + sw $fp,24($sp) + move $fp,$sp + jal ref1 + nop + + move $sp,$fp + lw $31,28($sp) + lw $fp,24($sp) + addiu $sp,$sp,32 + j $31 + nop + + .set macro + .set reorder + .end main + .size main, .-main + .ident "GCC: (GNU) 4.9.0 20130930 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-dyn-ref.s b/ld/testsuite/ld-mips-elf/ifunc-dyn-ref.s new file mode 100644 index 0000000..d562096 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-dyn-ref.s @@ -0,0 +1,43 @@ + .file 1 "ifunc_ref.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .text + .align 2 + .globl ref1 + .set nomips16 + .set nomicromips + .ent ref1 + .type ref1, @function +ref1: + .frame $fp,32,$31 # vars= 0, regs= 2/0, args= 16, gp= 8 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .cpload $25 + .set nomacro + addiu $sp,$sp,-32 + sw $31,28($sp) + sw $fp,24($sp) + move $fp,$sp + .cprestore 16 + lw $2,%call16(func1)($28) + move $25,$2 + jalr $25 + nop + + lw $28,16($fp) + move $sp,$fp + lw $31,28($sp) + lw $fp,24($sp) + addiu $sp,$sp,32 + j $31 + nop + + .set macro + .set reorder + .end ref1 + .size ref1, .-ref1 + .ident "GCC: (GNU) 4.9.0 20130930 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-dyn.ld b/ld/testsuite/ld-mips-elf/ifunc-dyn.ld new file mode 100644 index 0000000..c82c8ce --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-dyn.ld @@ -0,0 +1,25 @@ +ENTRY(_start) +SECTIONS +{ + . = ALIGN (0x400); + .text : { *(.text) } + + . = ALIGN (0x400); + .iplt : { *(.iplt) } + + . = ALIGN (0x400); + .igot : { *(.igot) } + + . = ALIGN (0x400); + .got : { *(.got) } + + . = ALIGN (0x400); + .data : { *(.data) } + + . = ALIGN (0x1000); + .rel.dyn : + { + *(.rel.*) + } + +} diff --git a/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000.t b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000.t new file mode 100644 index 0000000..c46a85d --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000.t @@ -0,0 +1,11 @@ +tmpdir/ifunc-iplt-0x400000: file format elf64-tradbigmips + + +Disassembly of section .iplt: + +0000000000400188 <.iplt.func1>: + 400188: 3c0f0041 lui t3,0x41 + 40018c: ddf90320 ld t9,800\(t3\) + 400190: 03200008 jr t9 + 400194: 00000000 nop + ... diff --git a/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000000.t b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000000.t new file mode 100644 index 0000000..3562b23 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x400000000.t @@ -0,0 +1,13 @@ +tmpdir/ifunc-iplt-0x400000000: file format elf64-tradbigmips + + +Disassembly of section .iplt: + +0000000400000188 <.iplt.func1>: + 400000188: 3c0f0004 lui t3,0x4 + 40000018c: 25ef0001 addiu t3,t3,1 + 400000190: 000f7c38 dsll t3,t3,0x10 + 400000194: ddf90320 ld t9,800\(t3\) + 400000198: 03200008 jr t9 + 40000019c: 00000000 nop + ... diff --git a/ld/testsuite/ld-mips-elf/ifunc-iplt-0x4000000000000.t b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x4000000000000.t new file mode 100644 index 0000000..90e8306 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-iplt-0x4000000000000.t @@ -0,0 +1,14 @@ +tmpdir/ifunc-iplt-0x4000000000000: file format elf64-tradbigmips + + +Disassembly of section .iplt: + +0004000000000188 <.iplt.func1>: + 4000000000188: 3c0f0004 lui t3,0x4 + 400000000018c: 3c0e0001 lui t2,0x1 + 4000000000190: 25ef0000 addiu t3,t3,0 + 4000000000194: 000f783c dsll32 t3,t3,0x0 + 4000000000198: 01ee782d daddu t3,t3,t2 + 400000000019c: ddf90320 ld t9,800\(t3\) + 40000000001a0: 03200008 jr t9 + 40000000001a4: 00000000 nop diff --git a/ld/testsuite/ld-mips-elf/ifunc-iplt.ld b/ld/testsuite/ld-mips-elf/ifunc-iplt.ld new file mode 100644 index 0000000..a26b803 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-iplt.ld @@ -0,0 +1,26 @@ +ENTRY(_start) +SECTIONS +{ + . = ALIGN (0x400); + .iplt : { *(.iplt) } + + . = ALIGN (0x400); + .text : { *(.text) } + + . = ALIGN (0x400); + .igot : { *(.igot) } + + . = ALIGN (0x400); + .got : { *(.got) } + + . = ALIGN (0x400); + .data : { *(.data) } + + . = ALIGN (0x1000); + .rel.dyn : + { + *(.rel.*) + } +/* /DISCARD/ : { *(*) } */ + +} diff --git a/ld/testsuite/ld-mips-elf/ifunc-static-def.s b/ld/testsuite/ld-mips-elf/ifunc-static-def.s new file mode 100644 index 0000000..cf84696 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-static-def.s @@ -0,0 +1,155 @@ + .file 1 "ifunc.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .option pic0 + .text + .align 2 + .set nomips16 + .set nomicromips + .ent f1_a + .type f1_a, @function +f1_a: + .frame $fp,8,$31 # vars= 0, regs= 1/0, args= 0, gp= 0 + .mask 0x40000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-8 + sw $fp,4($sp) + move $fp,$sp + li $2,1 # 0x1 + move $sp,$fp + lw $fp,4($sp) + addiu $sp,$sp,8 + j $31 + nop + + .set macro + .set reorder + .end f1_a + .size f1_a, .-f1_a + .align 2 + .set nomips16 + .set nomicromips + .ent f1_b + .type f1_b, @function +f1_b: + .frame $fp,8,$31 # vars= 0, regs= 1/0, args= 0, gp= 0 + .mask 0x40000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-8 + sw $fp,4($sp) + move $fp,$sp + li $2,2 # 0x2 + move $sp,$fp + lw $fp,4($sp) + addiu $sp,$sp,8 + j $31 + nop + + .set macro + .set reorder + .end f1_b + .size f1_b, .-f1_b + .align 2 + .set nomips16 + .set nomicromips + .ent f1_c + .type f1_c, @function +f1_c: + .frame $fp,8,$31 # vars= 0, regs= 1/0, args= 0, gp= 0 + .mask 0x40000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-8 + sw $fp,4($sp) + move $fp,$sp + li $2,3 # 0x3 + move $sp,$fp + lw $fp,4($sp) + addiu $sp,$sp,8 + j $31 + nop + + .set macro + .set reorder + .end f1_c + .size f1_c, .-f1_c + .align 2 + .globl func1_ifunc + .set nomips16 + .set nomicromips + .ent func1_ifunc + .type func1_ifunc, @function +func1_ifunc: + .frame $fp,432,$31 # vars= 400, regs= 2/0, args= 16, gp= 8 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-432 + sw $31,428($sp) + sw $fp,424($sp) + move $fp,$sp + addiu $2,$fp,28 + move $4,$2 + nop + + beq $2,$0,$L8 + nop + + li $2,48 # 0x30 + sw $2,24($fp) + j $L9 + nop + +$L8: + li $2,3 # 0x3 + sw $2,24($fp) +$L9: + lw $2,24($fp) + andi $2,$2,0xf0 + beq $2,$0,$L10 + nop + + lui $2,%hi(f1_a) + addiu $2,$2,%lo(f1_a) + j $L13 + nop + +$L10: + lw $2,24($fp) + andi $2,$2,0xf + beq $2,$0,$L12 + nop + + lui $2,%hi(f1_b) + addiu $2,$2,%lo(f1_b) + j $L13 + nop + +$L12: + lui $2,%hi(f1_c) + addiu $2,$2,%lo(f1_c) +$L13: + move $sp,$fp + lw $31,428($sp) + lw $fp,424($sp) + addiu $sp,$sp,432 + j $31 + nop + + .set macro + .set reorder + .end func1_ifunc + .size func1_ifunc, .-func1_ifunc + .globl func1 + .type func1, @gnu_indirect_function + func1 = func1_ifunc + .ident "GCC: (GNU) 4.9.0 20130930 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-static-main.s b/ld/testsuite/ld-mips-elf/ifunc-static-main.s new file mode 100644 index 0000000..2093a42 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-static-main.s @@ -0,0 +1,39 @@ + .file 1 "ifunc_ref_main_1.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .option pic0 + .text + .align 2 + .globl main + .set nomips16 + .set nomicromips + .ent main + .type main, @function +main: + .frame $fp,32,$31 # vars= 0, regs= 2/0, args= 16, gp= 8 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-32 + sw $31,28($sp) + sw $fp,24($sp) + move $fp,$sp + jal func1 + nop + + move $sp,$fp + lw $31,28($sp) + lw $fp,24($sp) + addiu $sp,$sp,32 + j $31 + nop + + .set macro + .set reorder + .end main + .size main, .-main + .ident "GCC: (GNU) 4.9.0 20130930 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-static-ref.s b/ld/testsuite/ld-mips-elf/ifunc-static-ref.s new file mode 100644 index 0000000..e17db14 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-static-ref.s @@ -0,0 +1,39 @@ + .file 1 "ifunc_ref.c" + .section .mdebug.abi32 + .previous + .nan legacy + .gnu_attribute 4, 1 + .abicalls + .option pic0 + .text + .align 2 + .globl ref1 + .set nomips16 + .set nomicromips + .ent ref1 + .type ref1, @function +ref1: + .frame $fp,32,$31 # vars= 0, regs= 2/0, args= 16, gp= 8 + .mask 0xc0000000,-4 + .fmask 0x00000000,0 + .set noreorder + .set nomacro + addiu $sp,$sp,-32 + sw $31,28($sp) + sw $fp,24($sp) + move $fp,$sp + jal func1 + nop + + move $sp,$fp + lw $31,28($sp) + lw $fp,24($sp) + addiu $sp,$sp,32 + j $31 + nop + + .set macro + .set reorder + .end ref1 + .size ref1, .-ref1 + .ident "GCC: (GNU) 4.9.0 20130930 (experimental)" diff --git a/ld/testsuite/ld-mips-elf/ifunc-static.ld b/ld/testsuite/ld-mips-elf/ifunc-static.ld new file mode 100644 index 0000000..ef07ec6 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/ifunc-static.ld @@ -0,0 +1,27 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x80000; + . = ALIGN (0x400); + .iplt : { *(.iplt) } + + . = ALIGN (0x400); + .text : { *(.text) } + + . = ALIGN (0x400); + .igot : { *(.igot) } + + . = ALIGN (0x400); + .got : { *(.got) } + + . = ALIGN (0x400); + .data : { *(.data) } + + . = ALIGN (0x1000); + .rel.dyn : + { + *(.rel.*) + } +/* /DISCARD/ : { *(*) } */ + +} diff --git a/ld/testsuite/ld-mips-elf/libifunc-1-n32.sym b/ld/testsuite/ld-mips-elf/libifunc-1-n32.sym new file mode 100644 index 0000000..88d7e5d --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-1-n32.sym @@ -0,0 +1,4 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 3 0: 0000000c 28 FUNC GLOBAL DEFAULT 1 func1_ifunc + 2 0: 0000000c 28 IFUNC GLOBAL DEFAULT 1 func1 diff --git a/ld/testsuite/ld-mips-elf/libifunc-1-n64.sym b/ld/testsuite/ld-mips-elf/libifunc-1-n64.sym new file mode 100644 index 0000000..7236950 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-1-n64.sym @@ -0,0 +1,4 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 3 0: 000000000000000c 28 FUNC GLOBAL DEFAULT 1 func1_ifunc + 2 0: 000000000000000c 28 IFUNC GLOBAL DEFAULT 1 func1 diff --git a/ld/testsuite/ld-mips-elf/libifunc-1-o32.sym b/ld/testsuite/ld-mips-elf/libifunc-1-o32.sym new file mode 100644 index 0000000..b5fff26 --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-1-o32.sym @@ -0,0 +1,4 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 3 0: 0000000c 40 FUNC GLOBAL DEFAULT 1 func1_ifunc + 2 0: 0000000c 40 IFUNC GLOBAL DEFAULT 1 func1 diff --git a/ld/testsuite/ld-mips-elf/libifunc-2-n32.sym b/ld/testsuite/ld-mips-elf/libifunc-2-n32.sym new file mode 100644 index 0000000..2c1e84e --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-2-n32.sym @@ -0,0 +1,4 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 2 0: 00000000 60 FUNC GLOBAL DEFAULT 1 ref1 + 3 0: 00000040 0 FUNC GLOBAL DEFAULT UND func1 diff --git a/ld/testsuite/ld-mips-elf/libifunc-2-n64.sym b/ld/testsuite/ld-mips-elf/libifunc-2-n64.sym new file mode 100644 index 0000000..3bd53fd --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-2-n64.sym @@ -0,0 +1,4 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 2 0: 0000000000000000 60 FUNC GLOBAL DEFAULT 1 ref1 + 3 0: 0000000000000040 0 FUNC GLOBAL DEFAULT UND func1 diff --git a/ld/testsuite/ld-mips-elf/libifunc-2-o32.sym b/ld/testsuite/ld-mips-elf/libifunc-2-o32.sym new file mode 100644 index 0000000..b831edd --- /dev/null +++ b/ld/testsuite/ld-mips-elf/libifunc-2-o32.sym @@ -0,0 +1,5 @@ +Symbol table for image: + Num Buc: Value Size Type Bind Vis Ndx Name + 3 0: 00000000 76 FUNC GLOBAL DEFAULT 1 ref1 + 4 0: 00000050 0 FUNC GLOBAL DEFAULT UND func1 + 2 0: 00000000 0 SECTION GLOBAL DEFAULT ABS _gp_disp diff --git a/ld/testsuite/ld-mips-elf/mips-ifunc.exp b/ld/testsuite/ld-mips-elf/mips-ifunc.exp new file mode 100644 index 0000000..ae389cf --- /dev/null +++ b/ld/testsuite/ld-mips-elf/mips-ifunc.exp @@ -0,0 +1,149 @@ +# Expect script for MIPS IFUNC linker tests +# Copyright 2013 +# Free Software Foundation, Inc. +# +# This file is part of the GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +if {![istarget mips*-*-*] || ![is_elf_format]} { + return +} + +# General setup +############################################# +set has_newabi [expr [istarget *-*-irix6*] \ + || [istarget mips*-*-linux*] \ + || [istarget mips*-sde-elf*]] +set linux_gnu [expr [istarget mips*-*-linux*]] +set embedded_elf [expr [istarget mips*-*-elf]] + +# Set defaults. +set abi_asflags(o32) "" +set abi_asflags(n32) "-march=from-abi -n32 -EB" +set abi_asflags(n64) "-march=from-abi -64 -EB" +set abi_ldflags(o32) "" +set abi_ldflags(n32) -melf32bmipn32 +set abi_ldflags(n64) -melf64bmip + +# Override as needed. +if { [istarget *-*-irix6*] } { + set abi_asflags(o32) "-32 -EB" + set abi_ldflags(o32) -melf32bsmip +} elseif { [istarget mips64*-linux*] } { + set abi_asflags(o32) "-32 -EB" + set abi_ldflags(o32) -melf32btsmip +} elseif { [istarget mips64*-*freebsd*] } { + set abi_asflags(o32) "-32 -EB" + set abi_ldflags(o32) -melf32btsmip_fbsd +} +if { [istarget mips*-*-linux*] || [istarget mips*-sde-elf*] } { + set abi_ldflags(n32) -melf32btsmipn32 + set abi_ldflags(n64) -melf64btsmip +} elseif { [istarget mips64*-*freebsd*] } { + set abi_ldflags(n32) -melf32btsmipn32_fbsd + set abi_ldflags(n64) -melf64btsmip_fbsd +} +############################################# + + +# STT_GNU_IFUNC testing: +# +# 1. Dso with ifunc defined code +# 2. Dso that references external ifunc'ed routines +# 3. Dynamic executable with ifunc defined code +# 4. Static executable with ifunc defined and referenced code +# 5. Dso with with ifunc defined and referenced code +# 6. Dynamic executable with ifunc defined and referenced code +# STT_GNU_IFUNC tests. +set abis [concat o32 [expr {$has_newabi ? "n32 n64" : ""}]] +foreach { abi } $abis { + run_ld_link_tests [list \ + [list \ + "IFUNC 1 (Simple dso with def) ${abi}" \ + "$abi_ldflags($abi) -shared -T ifunc-dyn.ld" "" \ + "$abi_asflags($abi)" \ + [list ifunc-dyn-def.s] \ + [list "readelf -Ds libifunc-1-${abi}.sym"] \ + "libifunc-1-${abi}.so" \ + ] \ + [list \ + "IFUNC 2 (Simple dso with ref) ${abi}" \ + "$abi_ldflags($abi) -shared -T ifunc-dyn.ld" "" \ + "$abi_asflags($abi)" \ + [list ifunc-dyn-ref.s] \ + [list "readelf -Ds libifunc-2-${abi}.sym"] \ + "libifunc-2-${abi}.so" \ + ] \ + [list \ + "IFUNC 3 (Simple dynamic executable with def) ${abi}" \ + "$abi_ldflags($abi) -Bdynamic -L./tmpdir -lifunc-2-${abi} -T ifunc-dyn.ld" "" \ + "$abi_asflags($abi)" \ + [list ifunc-dyn-main.s ifunc-dyn-def.s] \ + [list "readelf -Ds ifunc-3-${abi}.sym" \ + "readelf -r ifunc-3-${abi}.r" \ + "objdump -dj.iplt ifunc-3-${abi}.t"] \ + "ifunc-3-${abi}" \ + ] \ + [list \ + "IFUNC 4 (Simple static executable with def and ref) ${abi}" \ + "$abi_ldflags($abi) -Bstatic -T ifunc-static.ld" "" \ + "$abi_asflags($abi) -non_shared" \ + [list ifunc-static-main.s ifunc-static-def.s ifunc-static-ref.s] \ + [list "readelf -s ifunc-4-${abi}.sym" \ + "readelf -r ifunc-4-${abi}.r" \ + "objdump -dj.iplt ifunc-4-${abi}.t"] \ + "ifunc-4-${abi}" \ + ] \ + [list \ + "IFUNC 5 (Dynamic shared object with def and ref) ${abi}" \ + "$abi_ldflags($abi) -shared -T ifunc-dyn.ld" "" \ + "$abi_asflags($abi) -KPIC" \ + [list ifunc-dyn-def.s ifunc-dyn-ref.s] \ + [list "readelf -Ds ifunc-5-${abi}.sym" \ + "readelf -r ifunc-5-${abi}.r"] \ + "ifunc-5-${abi}" \ + ] \ + [list \ + "IFUNC 6 (Dynamic executable with def and ref) ${abi}" \ + "$abi_ldflags($abi) -Bdynamic -L./tmpdir -lifunc-2-${abi} -T ifunc-dyn.ld" "" \ + "$abi_asflags($abi)" \ + [list ifunc-dyn-main.s ifunc-dyn-def.s ifunc-dyn-ref.s] \ + [list "readelf -Ds ifunc-6-${abi}.sym" \ + "readelf -r ifunc-6-${abi}.r"] \ + "ifunc-6-${abi}" \ + ] \ + ] +} + +# IPLT sequences change based on how big the address of the +# .igot.plt section is based on Mips loading immediate values. +# +set addrs { "0x400000" "0x400000000" "0x4000000000000" } +foreach { addr } $addrs { + run_ld_link_tests [list \ + [list \ + "IFUNC IPLT (Simple static executable with def and ref) ${addr}" \ + "$abi_ldflags(n64) -Bstatic -Ttext-segment ${addr}" "" \ + "$abi_asflags(n64) -non_shared" \ + [list ifunc-static-main.s ifunc-static-def.s ifunc-static-ref.s] \ + [list "objdump -dj.iplt ifunc-iplt-${addr}.t"] \ + "ifunc-iplt-${addr}" \ + ] \ + ] +} + -- 1.7.9.5
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |