This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH 1/2] [RFC] Add IFUNC support for MIPS (v4)
- From: Faraz Shahbazker <faraz dot shahbazker at imgtec dot com>
- To: "Maciej W. Rozycki" <macro at imgtec dot com>
- Cc: "binutils at sourceware dot org" <binutils at sourceware dot org>, Richard Sandiford <rdsandiford at googlemail dot com>
- Date: Fri, 20 May 2016 19:01:13 -0700
- Subject: Re: [PATCH 1/2] [RFC] Add IFUNC support for MIPS (v4)
- Authentication-results: sourceware.org; auth=none
- References: <5583540C dot 7070800 at imgtec dot com> <87381jtr31 dot fsf at googlemail dot com> <55899D52 dot 1050000 at imgtec dot com> <87vbeegucz dot fsf at googlemail dot com> <5589AFCD dot 10905 at imgtec dot com> <DCB1C42372B1674B8F912A294CCB775A71680718 at BADAG02 dot ba dot imgtec dot org> <87615awnv8 dot fsf at googlemail dot com> <5600517C dot 1030608 at imgtec dot com> <874mig14xs dot fsf at googlemail dot com> <561D2820 dot 10107 at imgtec dot com> <871tc0acam dot fsf at googlemail dot com> <5678829D dot 4080108 at imgtec dot com> <877fk6jewx dot fsf at googlemail dot com> <568EFE7B dot 60708 at imgtec dot com> <alpine dot DEB dot 2 dot 00 dot 1602101549000 dot 15885 at tp dot orcam dot me dot uk> <alpine dot DEB dot 2 dot 00 dot 1604121439450 dot 21846 at tp dot orcam dot me dot uk>
On 04/29/16 06:57, Maciej W. Rozycki wrote:
>> diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
>> index 752f386..e8f1079 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 */>
> Also why `bfd_elf_generic_reloc' and not `_bfd_mips_elf_generic_reloc'?
I copied this bit directly from the previous series of MIPS IFUNC patches,
published a couple of years back. My guess is that it was selected based
on whatever architecture was used as a reference, without considering the
prevalent convention in MIPS-specific code. Will fix for the next iteration.
>> @@ -3691,18 +3938,28 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
>> return entry;
>> }
>>
>> - lookup.abfd = NULL;
>> lookup.symndx = -1;
>> - lookup.d.address = value;
>> + if (h && h->root.type == STT_GNU_IFUNC)
>> + {
>> + lookup.abfd = ibfd;
>> + lookup.d.h = h;
>> + }
>> + else
>> + {
>> + lookup.abfd = NULL;
>> + lookup.d.address = value;
>> + }
>> +
>> loc = htab_find_slot (g->got_entries, &lookup, INSERT);
>> if (!loc)
>> return NULL;
>>
>> entry = (struct mips_got_entry *) *loc;
>> - if (entry)
>> + if (entry && entry->gotidx >= 0)
>> return entry;
>
> Why do you need to check `entry->gotidx' now?
The local GOT entry could have been created earlier by
mips_elf_record_[global|local]_got_symbols(), but the gotidx is only assigned
from the general GOT pool, when mips_elf_create_local_got_entry() is called.
The major change here is that IFUNC GOT entries are always tracked uniquely
by the symbol's hash-table entry (d.h), as against other local symbols which
could by tracked by d.addend.
>> @@ -6279,6 +6717,7 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
>> && r_type == R_MIPS_26
>> && (x >> 26) == 0x3) /* jal addr */
>> || (JALR_TO_BAL_P (input_bfd)
>> + && !ifunc_p
>> && r_type == R_MIPS_JALR
>> && x == 0x0320f809) /* jalr t9 */
>> || (JR_TO_B_P (input_bfd)
>
> Why for JALR only and not JR?
>
> I think it'll be properly handled in `mips_elf_calculate_relocation'
> instead, by discarding R_MIPS_JALR (and R_MICROMIPS_JALR, the handling of
> which is currently incomplete, but should be fixed) relocations in the
> IFUNC case rather than making them reach this point and only noticing they
> shouldn't be here in the first place. So please arrange for this to
> happen along the case already handled there, rather than here.
We can in fact discard these relocs for all IFUNCs that do not have IPLTs,
since there is no canonical address to use for the optimization in that case.
A related problem to tackle -- these relocs count as static relocs and cause
IPLT stubs to be generated for locally bound IFUNCs, even when they are not
otherwise needed (that is, when all references are GOT-based).
>> @@ -6436,31 +6876,44 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd,
> <snip>
> No R_MIPS_IRELATIVE/R_MIPS_64 composition for n64?
I defined IRELATIVE to just operate on natural width, since it is operating on GOT
entries. Now that you've mentioned it, I agree that composition would keep things
closer to the ABI spec. The glibc patch will need to be modified as well.
>> @@ -7920,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;
>
> This sets `elf_hash_table (info)->dynobj' in a disguised way. Please
> sort out the assignment to `dynobj' immediately above then, and take care
> of code later on in this function which has become dead now.
I've moved this assignment of ->dynobj in to create_ifunc_sections() and arranged
for that function to be called at the end of _bfd_mips_elf_check_relocs(),
and only if an input object declares IFUNCs. This arrangement makes the
'not-generated-if-not-needed' comment above more accurate.
>> @@ -8398,7 +8885,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 && ih == NULL)
>> {
>> (*_bfd_error_handler)
>> (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
>
> Under which circumstances does this condition trigger for local ifuncs?
> CALL16 relocations are used for lazy binding and are explicitly defined in
> the MIPS psABI for external symbols only. Can the resolver for a local
> ifunc be external and bind lazily?
Local IFUNCs are treated like global symbols in that they get a full GOT
(or IGOT) entry each and all references must go through that GOT entry.
This means that call16/got16 references can theoretically work for local
IFUNCs, although not explicitly sanctioned by the ABI.
I just followed gcc's behaviour instead of referring to the ABI on this
point. gcc does not consider IFUNCs to be locally bound, since the
resolved function could be external. The mips backend, using this criteria,
considers all IFUNCs to be candidates for lazy evaluation and emits call16
for all PIC IFUNC calls without caring about local vs. global binding.
This trips up the error condition above.
Since you pointed it out, I tinkered around with gcc to force got16 to be
generated for local IFUNCs instead of call16, but ran up against instances
where it is impossible to know that the symbol is a local IFUNC. For example,
the glibc testsuite has IFUNC declarations like this:
extern int foo (void);
static void * foo_ifunc (void) __asm__ ("foo");
__asm__(".type foo, %gnu_indirect_function");
Both `static' and `ifunc' aspects of foo are hidden in inline assembly
and hence not available to the compiler. I don't see a way around this.
We can modify gcc to generate the right reloc for the canonical
local IFUNC declaration and let ^^those glibc tests fail, till such time
when they are modified to use the canonical form (not an easy sell, given
the pretzel declaration above seems to work for other architectures).
This reminds me, another issue with gcc is that it generates GOT+LO16
sequence for non-call references to local IFUNC instead of just GOT().
The GOT load already gives the address of the IFUNC and the subsequent
addiu corrupts it. I'll upload a gcc patch to address both issues and
copy you on it for comments.
Considering that this is an `extension', I think it would be okay to
allow CALL16 on local IFUNCs. But I'll follow your cue on what to
do about it.
Regards,
Faraz Shahbazker