[PATCH] ld/elf: Don't take IFUNC address in the shared object
Fangrui Song
i@maskray.me
Sat Jan 16 20:53:21 GMT 2021
On 2021-01-16, H.J. Lu via Binutils wrote:
>On x86, glibc 2.33 starts to issue a fatal error message when calling
>IFUNC function defined in the unrelocated executable from a shared
>library.
>
>1. Update x86 ELF linker to always convert IFUNC function defined in
>position-dependent executable (PDE) to the normal function. GOT in PDE
>will be updated by R_*_IRELATIVE at run-time.
>2. Update PR ld/23169 tests not to compare function address of external
>IFUNC function in the shared object to avoid calling the IFUNC function
>defined in the unrelocated executable.
I think the description is less clear.
If the declaration (defined as ifunc in another translation unit) is always
referenced via GOT-generating or PLT-generating relocation types,
there is no need converting it to STT_FUNC.
I guess the original instructions in
https://sourceware.org/bugzilla/show_bug.cgi?id=23169#c0 missed -fno-pic
because many x86-64 Linux distributions default to -fpie now.
-fpie uses R_X86_64_REX_GOTPCRELX to take a function pointer. It likely
worked before PR23169.
-fno-pic uses R_X86_64_32S which needed a fix in PR23169.
It is unclear whether something regressed the PR23169 fix or the PR23169 fix was incomplete.
>bfd/
>
> PR ld/23169
> * elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): Don't
> check pointer_equality_needed.
>
>ld/
>
> PR ld/23169
> * testsuite/ld-ifunc/ifunc.exp: Replace pr23169c.rd with
> pr23169a.rd for pr23169c and pr23169f. Remove pr23169e tests.
> * testsuite/ld-ifunc/pr23169a.c: Don't take function address.
>---
> bfd/elfxx-x86.c | 3 +--
> ld/testsuite/ld-ifunc/ifunc.exp | 22 ++--------------------
> ld/testsuite/ld-ifunc/pr23169a.c | 2 +-
> 3 files changed, 4 insertions(+), 23 deletions(-)
>
>diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
>index 8cda8d2d97c..93ad38c5eb0 100644
>--- a/bfd/elfxx-x86.c
>+++ b/bfd/elfxx-x86.c
>@@ -1711,8 +1711,7 @@ _bfd_x86_elf_link_fixup_ifunc_symbol (struct bfd_link_info *info,
> && h->def_regular
> && h->dynindx != -1
> && h->plt.offset != (bfd_vma) -1
>- && h->type == STT_GNU_IFUNC
>- && h->pointer_equality_needed)
>+ && h->type == STT_GNU_IFUNC)
> {
> asection *plt_s;
> bfd_vma plt_offset;
>diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp
>index 31666d0f29c..9d3ace65216 100644
>--- a/ld/testsuite/ld-ifunc/ifunc.exp
>+++ b/ld/testsuite/ld-ifunc/ifunc.exp
>@@ -640,7 +640,7 @@ run_cc_link_tests [list \
> "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
> "-fPIE -O2 -g" \
> { pr23169b.c pr23169c.c } \
>- {{readelf {--dyn-syms} pr23169c.rd} \
>+ {{readelf {--dyn-syms} pr23169a.rd} \
> {readelf {-r -W} pr23169b.rd}} \
> "pr23169c" \
> ] \
>@@ -653,21 +653,12 @@ run_cc_link_tests [list \
> {readelf {-r -W} pr23169b.rd}} \
> "pr23169d" \
> ] \
>- [list \
>- "Build pr23169e" \
>- "-pie -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
>- "-fPIE -O2 -g" \
>- { pr23169b.c pr23169c.c } \
>- {{readelf {--dyn-syms} pr23169c.rd} \
>- {readelf {-r -W} pr23169b.rd}} \
>- "pr23169e" \
>- ] \
> [list \
> "Build pr23169f" \
> "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
> "-fPIE -O2 -g" \
> { pr23169b.c pr23169c.c } \
>- {{readelf {--dyn-syms} pr23169c.rd} \
>+ {{readelf {--dyn-syms} pr23169a.rd} \
> {readelf {-r -W} pr23169b.rd}} \
> "pr23169f" \
> ] \
>@@ -774,15 +765,6 @@ run_ld_link_exec_tests [list \
> "pass.out" \
> "$NOPIE_CFLAGS -O2 -g" \
> ] \
>- [list \
>- "Run pr23169e" \
>- "-pie -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
>- "" \
>- { pr23169b.c pr23169c.c } \
>- "pr23169e" \
>- "pass.out" \
>- "-fPIE -O2 -g" \
>- ] \
> [list \
> "Run pr23169f" \
> "$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
>diff --git a/ld/testsuite/ld-ifunc/pr23169a.c b/ld/testsuite/ld-ifunc/pr23169a.c
>index 02bf2208904..8beed283bc8 100644
>--- a/ld/testsuite/ld-ifunc/pr23169a.c
>+++ b/ld/testsuite/ld-ifunc/pr23169a.c
>@@ -4,6 +4,6 @@ extern int func (void);
> void
> foo (void)
> {
>- if (func_p != &func || func_p () != 0xbadbeef)
>+ if (func () != 0xbadbeef || func_p () != 0xbadbeef)
> __builtin_abort ();
> }
There is lost test coverage. func_p != &func is untested now.
More information about the Binutils
mailing list