[PATCH 00/11] alpha: support STT_GNU_IFUNC

Matt Turner <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
The alpha linker does not support indirect functions.  This series adds
that support, along with the dynamic relocation it needs, and turns on
the ld-ifunc tests.

An IFUNC needs a dynamic relocation that stores the value a resolver
returns, so patch 3 allocates R_ALPHA_IRELATIVE as relocation type 42,
the first number the target has not used.  A matching glibc patch,
posted to libc-alpha [1], adds the same number and applies the
relocation.  No dynamic linker or C library startup code implements it
today, which ld/NEWS says: a program that uses an indirect function
needs a matching C library to run.  Until then the GOT entry or data
word holds the address of the resolver, which is what alpha does with an
IFUNC now, so nothing that links today gets worse.

Alpha treats an IFUNC like an ordinary function, so every reference the
linker resolves itself currently ends up with the address of the
resolver rather than of the function it selects.  In a PIC link that
address is written by an R_ALPHA_RELATIVE, for a GOT entry or a data
word whose symbol binds locally; patch 5 emits an R_ALPHA_IRELATIVE in
its place.  Space for the RELATIVE is already reserved in the same
section, so the sizing does not change.  A preemptible IFUNC is left
alone: the dynamic linker resolves it, and a PLT entry with a JMP_SLOT
is what it wants, exactly as for an STT_FUNC.

A non-PIC link reserves no dynamic relocation for a reference it
resolves itself, so there is nothing there to turn into an
R_ALPHA_IRELATIVE.  Patch 7 puts those in a new .rela.iplt, which the
linker script places with the other dynamic relocations: ld.so applies
it along with the rest of .rela.dyn, and in a static executable libc
applies the range between __rela_iplt_start and __rela_iplt_end.

Unlike .rela.dyn, .rela.iplt has to be sized exactly, because libc
applies every entry of it: a slot that is reserved and then not filled
in is an R_ALPHA_NONE that its startup code chokes on.  check_relocs
cannot do that sizing.  It runs before a linker script has had the
chance to discard an input section, and only the sections that survive
into the output are relocated, so counting there over-reserves.  The
sizing therefore runs in late_size_sections, over the sections that
survived, marking the GOT entry each surviving reference reaches and
counting the data references.  The GOT entries are counted again on each
relaxation trip, since re-merging the GOTs can still combine two entries
of a global IFUNC into one.

A non-dynamic IFUNC gets no PLT entry, like any other non-dynamic
function.  Giving it one would put the IRELATIVE in DT_JMPREL, where the
dynamic linker expects a JMP_SLOT, and would leave a static link filling
in a PLT that nothing branches to.

That leaves three cases that alpha cannot express.  Each one is now
diagnosed:

  - A relocation that names the symbol directly, R_ALPHA_BRADDR,
    R_ALPHA_BRSGP, the gp-relative relocations and the pc-relative
    R_ALPHA_SREL*, reaches the resolver rather than the function it
    selects.  R_ALPHA_REFLONG names it indirectly but has no room for
    the address.  Patch 6 rejects them, reporting all of them in one
    link instead of stopping at the first.

  - The address of an IFUNC in a read-only section needs a read-only
    page relocated, which is DT_TEXTREL in a dynamic link but has
    nothing to do it in a static one: libc's startup code runs after the
    kernel has mapped the segment.  Other targets hand out the address
    of a PLT stub; alpha has no PLT entry for a non-dynamic function, so
    patch 8 reports it.

  - An R_ALPHA_IRELATIVE carries the address of the resolver in its
    addend, leaving no room for an offset from the symbol, so patch 10
    rejects a non-zero addend on a reference that gets one.  A reference
    the dynamic linker resolves keeps the addend of the symbolic
    relocation it gets instead and is unaffected.

Patch 9 covers the one way left to reserve a .rela.iplt slot and then
not fill it: .eh_frame editing deletes the place of a relocation long
after the section has been sized and given an address.  It reports that
reference, and has final_link compare the slots reserved against the
slots written as a consistency check on the sizing.

The first four patches are preparation and stand on their own: a new GOT
entry left two fields uninitialized, DT_TEXTREL was being set in
info->flags where DF_TEXTREL belongs, R_ALPHA_IRELATIVE is allocated,
and the code that names a symbol for a diagnostic is factored out and
replaced by bfd_elf_sym_name.

Testing: built with an alpha-linux-gnu cross toolchain.  The series adds
41 link tests to ld-alpha, covering local and global IFUNCs in static,
dynamic, shared and PIE links, GOT and data references, relaxation,
--gc-sections, discarded and COMDAT sections, .eh_frame editing,
-z combreloc and -z text, and each of the diagnostics above.  Removing
alpha from the skip list in ld-ifunc/ifunc.exp runs that directory's
link tests too; ifunc-26 stays the expected failure it has been since
commit bb4e012ca04, which is a gas .set limitation and not a linker
one.  The full ld testsuite is 1555 PASS with no failures, and the
binutils testsuite is unchanged.

[1] https://sourceware.org/pipermail/libc-alpha/2026-August/179703.html

Matt Turner (11):
  alpha: initialize every field of a new got entry
  alpha: set DF_TEXTREL rather than DT_TEXTREL in info->flags
  alpha: allocate R_ALPHA_IRELATIVE
  alpha: factor out elf64_alpha_sym_name
  alpha: emit R_ALPHA_IRELATIVE in PIC links
  alpha: reject relocations that cannot refer to an IFUNC
  alpha: support IFUNC symbols in non-PIC links
  alpha: reject an IFUNC address in read-only data in a static link
  alpha: diagnose a reference to an IFUNC whose place is deleted
  alpha: reject a non-zero addend on a reference to an IFUNC
  alpha: run the ld-ifunc tests

 bfd/elf64-alpha.c                             | 576 +++++++++++++++++-
 include/elf/alpha.h                           |   2 +
 ld/NEWS                                       |   7 +
 ld/testsuite/ld-alpha/alpha.exp               |   6 +
 ld/testsuite/ld-alpha/ifunc-addend-literal.d  |   3 +
 ld/testsuite/ld-alpha/ifunc-addend-literal.s  |  19 +
 ld/testsuite/ld-alpha/ifunc-addend-local.s    |  13 +
 ld/testsuite/ld-alpha/ifunc-addend-refquad.d  |   3 +
 ld/testsuite/ld-alpha/ifunc-addend-refquad.s  |  20 +
 .../ld-alpha/ifunc-addend-shared-local.d      |   3 +
 ld/testsuite/ld-alpha/ifunc-addend-shared.d   |  11 +
 ld/testsuite/ld-alpha/ifunc-branch.d          |   3 +
 ld/testsuite/ld-alpha/ifunc-branch.s          |  17 +
 ld/testsuite/ld-alpha/ifunc-comdat-a.s        |  11 +
 ld/testsuite/ld-alpha/ifunc-comdat-b.s        |  14 +
 ld/testsuite/ld-alpha/ifunc-comdat.d          |   4 +
 ld/testsuite/ld-alpha/ifunc-discard.d         |  11 +
 ld/testsuite/ld-alpha/ifunc-discard.ld        |   4 +
 ld/testsuite/ld-alpha/ifunc-discard.s         |  33 +
 ld/testsuite/ld-alpha/ifunc-ehframe-a.s       |  19 +
 ld/testsuite/ld-alpha/ifunc-ehframe-b.s       |  10 +
 ld/testsuite/ld-alpha/ifunc-ehframe.d         |   4 +
 ld/testsuite/ld-alpha/ifunc-extern.d          |  14 +
 ld/testsuite/ld-alpha/ifunc-extern.s          |  16 +
 ld/testsuite/ld-alpha/ifunc-gc-local.d        |   8 +
 ld/testsuite/ld-alpha/ifunc-gc-local.s        |  32 +
 ld/testsuite/ld-alpha/ifunc-gc.d              |   8 +
 ld/testsuite/ld-alpha/ifunc-gc.s              |  32 +
 ld/testsuite/ld-alpha/ifunc-global-dynamic.d  |   9 +
 ld/testsuite/ld-alpha/ifunc-global-export.d   |  12 +
 .../ld-alpha/ifunc-global-nocombreloc.d       |   9 +
 ld/testsuite/ld-alpha/ifunc-global-pie.d      |   9 +
 ld/testsuite/ld-alpha/ifunc-global-relax.d    |  15 +
 ld/testsuite/ld-alpha/ifunc-global-shared.d   |  12 +
 ld/testsuite/ld-alpha/ifunc-global-static.d   |  17 +
 ld/testsuite/ld-alpha/ifunc-global.s          |  24 +
 ld/testsuite/ld-alpha/ifunc-gprel.d           |   3 +
 ld/testsuite/ld-alpha/ifunc-gprel.s           |  18 +
 ld/testsuite/ld-alpha/ifunc-gprel32.d         |   3 +
 ld/testsuite/ld-alpha/ifunc-gprel32.s         |  17 +
 .../ld-alpha/ifunc-local-call-shared.d        |   8 +
 .../ld-alpha/ifunc-local-call-static.d        |   8 +
 ld/testsuite/ld-alpha/ifunc-local-call.s      |  17 +
 ld/testsuite/ld-alpha/ifunc-local-dynamic.d   |   9 +
 ld/testsuite/ld-alpha/ifunc-local-relax.d     |  16 +
 ld/testsuite/ld-alpha/ifunc-local-shared.d    |   9 +
 ld/testsuite/ld-alpha/ifunc-local-static.d    |  17 +
 ld/testsuite/ld-alpha/ifunc-local.s           |  25 +
 ld/testsuite/ld-alpha/ifunc-multi-a.s         |  24 +
 ld/testsuite/ld-alpha/ifunc-multi-b.s         |  16 +
 ld/testsuite/ld-alpha/ifunc-multi.d           |  13 +
 ld/testsuite/ld-alpha/ifunc-none.d            |   7 +
 ld/testsuite/ld-alpha/ifunc-none.s            |  12 +
 ld/testsuite/ld-alpha/ifunc-reflong-dynamic.d |   3 +
 ld/testsuite/ld-alpha/ifunc-reflong-static.d  |   3 +
 ld/testsuite/ld-alpha/ifunc-reflong.s         |  26 +
 ld/testsuite/ld-alpha/ifunc-relax-a.s         |  32 +
 ld/testsuite/ld-alpha/ifunc-relax-b.s         |  47 ++
 ld/testsuite/ld-alpha/ifunc-relax-discard.d   |  14 +
 ld/testsuite/ld-alpha/ifunc-relax-discard.s   |  41 ++
 ld/testsuite/ld-alpha/ifunc-relax.d           |  14 +
 ld/testsuite/ld-alpha/ifunc-rodata-dynamic.d  |  12 +
 ld/testsuite/ld-alpha/ifunc-rodata-static.d   |   3 +
 ld/testsuite/ld-alpha/ifunc-rodata-ztext.d    |   4 +
 ld/testsuite/ld-alpha/ifunc-rodata.s          |  22 +
 ld/testsuite/ld-alpha/ifunc-shlib.s           |   9 +
 ld/testsuite/ld-alpha/ifunc-srel.d            |   3 +
 ld/testsuite/ld-alpha/ifunc-srel.s            |  19 +
 ld/testsuite/ld-alpha/ifunc-weak-dynamic.d    |   9 +
 ld/testsuite/ld-alpha/ifunc-weak-static.d     |   9 +
 .../ld-alpha/ifunc-weak-undef-dynamic.d       |   5 +
 .../ld-alpha/ifunc-weak-undef-static.d        |   5 +
 ld/testsuite/ld-alpha/ifunc-weak-undef.s      |  22 +
 ld/testsuite/ld-alpha/ifunc-weak.s            |  24 +
 ld/testsuite/ld-alpha/textrel.d               |   9 +
 ld/testsuite/ld-alpha/textrel.s               |  13 +
 ld/testsuite/ld-ifunc/ifunc.exp               |   1 -
 77 files changed, 1550 insertions(+), 31 deletions(-)
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-literal.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-literal.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-local.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-refquad.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-refquad.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-shared-local.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-shared.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-branch.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-branch.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-comdat-a.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-comdat-b.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-comdat.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-discard.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-discard.ld
 create mode 100644 ld/testsuite/ld-alpha/ifunc-discard.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe-a.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe-b.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-extern.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-extern.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gc-local.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gc-local.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gc.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gc.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-export.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-nocombreloc.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-pie.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-relax.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-shared.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-global.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gprel.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gprel.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gprel32.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-gprel32.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-call-shared.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-call-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-call.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-relax.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-shared.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-local.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-multi-a.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-multi-b.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-multi.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-none.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-none.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-reflong-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-reflong-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-reflong.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-relax-a.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-relax-b.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-relax-discard.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-relax-discard.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-relax.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-rodata-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-rodata-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-rodata-ztext.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-rodata.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-shlib.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-srel.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-srel.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak-undef-dynamic.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak-undef-static.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak-undef.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-weak.s
 create mode 100644 ld/testsuite/ld-alpha/textrel.d
 create mode 100644 ld/testsuite/ld-alpha/textrel.s

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.