[PATCH] x86; Allow IFUNC pointer defined in PDE
H.J. Lu
hongjiu.lu@intel.com
Fri May 11 17:50:00 GMT 2018
If STT_GNU_IFUNC symbol is defined in position-dependent executable, we
should change it to the normal function and set its address to its PLT
entry which should be resolved by R_*_IRELATIVE at run-time. All
external references should be resolved to its PLT in executable.
The type field is added to elf_x86_link_hash_entry to keep track of the
originl symbol file. elf_x86_allocate_dynrelocs is updated to change
IFUNC symbol defined in PDE to FUNC and its address will be changed
to its PLT entry by _bfd_x86_elf_link_fixup_ifunc_symbol.
Any comments?
H.J.
---
bfd/
PR ld/23169
* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Don't issue
an error on IFUNC pointer defined in PDE.
* elf32-i386.c (elf_i386_check_relocs): Copy h->type to
eh->type.
(elf_i386_relocate_section): Check eh->type instead of h->type.
(elf_i386_finish_dynamic_symbol): Pass eh to PLT_LOCAL_IFUNC_P.
Call _bfd_x86_elf_link_fixup_ifunc_symbol. Check eh->type
instead of h->type.
* elf64-x86-64.c (elf_x86_64_check_relocs): Copy h->type to
eh->type.
(elf_x86_64_relocate_section): Check eh->type instead of h->type.
(elf_x86_64_finish_dynamic_symbol): Pass eh to PLT_LOCAL_IFUNC_P.
Call _bfd_x86_elf_link_fixup_ifunc_symbol. Check eh->type
instead of h->type.
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Change IFUNC symbol
defined in PDE to FUNC.
(_bfd_x86_elf_link_fixup_ifunc_symbol): New function.
* elfxx-x86.h (PLT_LOCAL_IFUNC_P): Take EH instead of H.
(elf_x86_link_hash_entry): Add type.
(_bfd_x86_elf_link_fixup_ifunc_symbol): New.
ld/
PR ld/23169
* testsuite/ld-ifunc/ifunc-9-i386.d: New file.
* testsuite/ld-ifunc/ifunc-9-x86-64.d: Likewise.
* testsuite/ld-ifunc/pr23169a.c: Likewise.
* testsuite/ld-ifunc/pr23169a.rd: Likewise.
* testsuite/ld-ifunc/pr23169b.c: Likewise.
* testsuite/ld-ifunc/pr23169b.c: Likewise.
* testsuite/ld-ifunc/pr23169c.rd: Likewise.
* testsuite/ld-ifunc/pr23169c.rd: Likewise.
* testsuite/ld-ifunc/ifunc-9-x86.d: Removed.
* testsuite/ld-ifunc/ifunc.exp: Run PR ld/23169 tests.
---
bfd/elf-ifunc.c | 9 +++-
bfd/elf32-i386.c | 14 ++++--
bfd/elf64-x86-64.c | 22 +++++----
bfd/elfxx-x86.c | 65 ++++++++++++++++++++++++--
bfd/elfxx-x86.h | 17 +++++--
ld/testsuite/ld-ifunc/ifunc-9-i386.d | 9 ++++
ld/testsuite/ld-ifunc/ifunc-9-x86-64.d | 9 ++++
ld/testsuite/ld-ifunc/ifunc-9-x86.d | 3 --
ld/testsuite/ld-ifunc/ifunc.exp | 44 +++++++++++++++++
ld/testsuite/ld-ifunc/pr23169a.c | 9 ++++
ld/testsuite/ld-ifunc/pr23169a.rd | 6 +++
ld/testsuite/ld-ifunc/pr23169b.c | 23 +++++++++
ld/testsuite/ld-ifunc/pr23169b.rd | 3 ++
ld/testsuite/ld-ifunc/pr23169c.c | 13 ++++++
ld/testsuite/ld-ifunc/pr23169c.rd | 6 +++
15 files changed, 224 insertions(+), 28 deletions(-)
create mode 100644 ld/testsuite/ld-ifunc/ifunc-9-i386.d
create mode 100644 ld/testsuite/ld-ifunc/ifunc-9-x86-64.d
delete mode 100644 ld/testsuite/ld-ifunc/ifunc-9-x86.d
create mode 100644 ld/testsuite/ld-ifunc/pr23169a.c
create mode 100644 ld/testsuite/ld-ifunc/pr23169a.rd
create mode 100644 ld/testsuite/ld-ifunc/pr23169b.c
create mode 100644 ld/testsuite/ld-ifunc/pr23169b.rd
create mode 100644 ld/testsuite/ld-ifunc/pr23169c.c
create mode 100644 ld/testsuite/ld-ifunc/pr23169c.rd
diff --git a/bfd/elf-ifunc.c b/bfd/elf-ifunc.c
index 5716ab36f1..b8a3632095 100644
--- a/bfd/elf-ifunc.c
+++ b/bfd/elf-ifunc.c
@@ -131,8 +131,15 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
the resolved function may be used. But in non-PIC executable,
the address of its .plt slot may be used. Pointer equality may
not work correctly. PIE or non-PLT reference should be used if
- pointer equality is required here. */
+ pointer equality is required here.
+
+ If STT_GNU_IFUNC symbol is defined in position-dependent executable,
+ backend should change it to the normal function and set its address
+ to its PLT entry which should be resolved by R_*_IRELATIVE at
+ run-time. All external references should be resolved to its PLT in
+ executable. */
if (!need_dynreloc
+ && !(bfd_link_pde (info) && h->def_regular)
&& (h->dynindx != -1
|| info->export_dynamic)
&& h->pointer_equality_needed)
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index c1c4ed0237..ad079eb43b 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -1564,6 +1564,8 @@ elf_i386_check_relocs (bfd *abfd,
/* It is referenced by a non-shared object. */
h->ref_regular = 1;
+ eh->type = h->type;
+
if (h->type == STT_GNU_IFUNC)
elf_tdata (info->output_bfd)->has_gnu_symbols
|= elf_gnu_symbol_ifunc;
@@ -2212,7 +2214,7 @@ elf_i386_relocate_section (bfd *output_bfd,
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
it here if it is defined in a non-shared object. */
if (h != NULL
- && h->type == STT_GNU_IFUNC
+ && eh->type == STT_GNU_IFUNC
&& h->def_regular)
{
asection *gotplt, *base_got;
@@ -2671,7 +2673,7 @@ disallow_got32:
return FALSE;
}
else if (!SYMBOL_REFERENCES_LOCAL_P (info, h)
- && (h->type == STT_FUNC
+ && (eh->type == STT_FUNC
|| h->type == STT_OBJECT)
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
{
@@ -2680,7 +2682,7 @@ disallow_got32:
(_("%pB: relocation R_386_GOTOFF against protected %s"
" `%s' can not be used when making a shared object"),
input_bfd,
- h->type == STT_FUNC ? "function" : "data",
+ eh->type == STT_FUNC ? "function" : "data",
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
@@ -3703,7 +3705,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
rel.r_offset = (gotplt->output_section->vma
+ gotplt->output_offset
+ got_offset);
- if (PLT_LOCAL_IFUNC_P (info, h))
+ if (PLT_LOCAL_IFUNC_P (info, eh))
{
info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
h->root.root.string,
@@ -3805,6 +3807,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
+ _bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
+
/* Don't generate dynamic GOT relocation against undefined weak
symbol in executable. */
if (h->got.offset != (bfd_vma) -1
@@ -3831,7 +3835,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
The entry in the global offset table will already have been
initialized in the relocate_section function. */
if (h->def_regular
- && h->type == STT_GNU_IFUNC)
+ && eh->type == STT_GNU_IFUNC)
{
if (h->plt.offset == (bfd_vma) -1)
{
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index a0ebd2cf69..97af71cf9e 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -1905,11 +1905,14 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
break;
}
+ eh = (struct elf_x86_link_hash_entry *) h;
if (h != NULL)
{
/* It is referenced by a non-shared object. */
h->ref_regular = 1;
+ eh->type = h->type;
+
if (h->type == STT_GNU_IFUNC)
elf_tdata (info->output_bfd)->has_gnu_symbols
|= elf_gnu_symbol_ifunc;
@@ -1941,7 +1944,6 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (h == htab->elf.hgot)
htab->got_referenced = TRUE;
- eh = (struct elf_x86_link_hash_entry *) h;
switch (r_type)
{
case R_X86_64_TLSLD:
@@ -2499,7 +2501,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
it here if it is defined in a non-shared object. */
if (h != NULL
- && h->type == STT_GNU_IFUNC
+ && eh->type == STT_GNU_IFUNC
&& h->def_regular)
{
bfd_vma plt_index;
@@ -2904,7 +2906,7 @@ skip_ifunc:
}
else if (!bfd_link_executable (info)
&& !SYMBOL_REFERENCES_LOCAL_P (info, h)
- && (h->type == STT_FUNC
+ && (eh->type == STT_FUNC
|| h->type == STT_OBJECT)
&& ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
{
@@ -2913,7 +2915,7 @@ skip_ifunc:
(_("%pB: relocation R_X86_64_GOTOFF64 against protected %s"
" `%s' can not be used when making a shared object"),
input_bfd,
- h->type == STT_FUNC ? "function" : "data",
+ eh->type == STT_FUNC ? "function" : "data",
h->root.root.string);
bfd_set_error (bfd_error_bad_value);
return FALSE;
@@ -3065,7 +3067,7 @@ use_plt:
reachable at run-time. */
fail = (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED
- && h->type == STT_FUNC));
+ && eh->type == STT_FUNC));
}
if (fail)
@@ -3077,7 +3079,7 @@ use_plt:
else if (h != NULL
&& (input_section->flags & SEC_CODE) == 0
&& bfd_link_pie (info)
- && h->type == STT_FUNC
+ && eh->type == STT_FUNC
&& !h->def_regular
&& h->def_dynamic)
goto use_plt;
@@ -4029,7 +4031,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
rela.r_offset = (gotplt->output_section->vma
+ gotplt->output_offset
+ got_offset);
- if (PLT_LOCAL_IFUNC_P (info, h))
+ if (PLT_LOCAL_IFUNC_P (info, eh))
{
info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
h->root.root.string,
@@ -4093,7 +4095,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
got_offset = h->got.offset;
if (got_offset == (bfd_vma) -1
- || (h->type == STT_GNU_IFUNC && h->def_regular)
+ || (eh->type == STT_GNU_IFUNC && h->def_regular)
|| plt == NULL
|| got == NULL)
abort ();
@@ -4147,6 +4149,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
+ _bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
+
/* Don't generate dynamic GOT relocation against undefined weak
symbol in executable. */
if (h->got.offset != (bfd_vma) -1
@@ -4172,7 +4176,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
The entry in the global offset table will already have been
initialized in the relocate_section function. */
if (h->def_regular
- && h->type == STT_GNU_IFUNC)
+ && eh->type == STT_GNU_IFUNC)
{
if (h->plt.offset == (bfd_vma) -1)
{
diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c
index 40157b8ed7..b6a38d24f8 100644
--- a/bfd/elfxx-x86.c
+++ b/bfd/elfxx-x86.c
@@ -140,13 +140,23 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
TRUE))
{
asection *s = htab->plt_second;
- if (h->plt.offset != (bfd_vma) -1 && s != NULL)
+ if (h->plt.offset != (bfd_vma) -1)
{
- /* Use the second PLT section if it is created. */
- eh->plt_second.offset = s->size;
+ if (s != NULL)
+ {
+ /* Use the second PLT section if it is created. */
+ eh->plt_second.offset = s->size;
+
+ /* Make room for this entry in the second PLT
+ section. */
+ s->size += htab->non_lazy_plt->plt_entry_size;
+ }
- /* Make room for this entry in the second PLT section. */
- s->size += htab->non_lazy_plt->plt_entry_size;
+ /* Change IFUNC symbol defined in PDE to FUNC. Later,
+ _bfd_x86_elf_link_fixup_ifunc_symbol will set its
+ address to its PLT entry, */
+ if (bfd_link_pde (info) && h->dynindx != -1)
+ h->type = STT_FUNC;
}
return TRUE;
@@ -1705,6 +1715,51 @@ _bfd_x86_elf_fixup_symbol (struct bfd_link_info *info,
return TRUE;
}
+/* Change the STT_GNU_IFUNC symbol into the normal function symbol
+ and set its address to its PLT entry, which should be resolved
+ by R_*_IRELATIVE at run-time, if it is defined in executable. */
+
+void
+_bfd_x86_elf_link_fixup_ifunc_symbol (struct bfd_link_info *info,
+ struct elf_x86_link_hash_table *htab,
+ struct elf_link_hash_entry *h,
+ Elf_Internal_Sym *sym)
+{
+ struct elf_x86_link_hash_entry *eh;
+
+ if (!bfd_link_pde (info)
+ || !h->def_regular
+ || h->dynindx == -1
+ || h->plt.offset == (bfd_vma) -1)
+ return;
+
+ eh = (struct elf_x86_link_hash_entry *) h;
+ if (eh->type == STT_GNU_IFUNC)
+ {
+ asection *plt_s;
+ bfd_vma plt_offset;
+ bfd *output_bfd = info->output_bfd;
+
+ if (htab->plt_second)
+ {
+ plt_s = htab->plt_second;
+ plt_offset = eh->plt_second.offset;
+ }
+ else
+ {
+ plt_s = htab->elf.splt;
+ plt_offset = h->plt.offset;
+ }
+
+ sym->st_size = 0;
+ sym->st_shndx
+ = _bfd_elf_section_from_bfd_section (output_bfd,
+ plt_s->output_section);
+ sym->st_value = (plt_s->output_section->vma
+ + plt_s->output_offset + plt_offset);
+ }
+}
+
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
bfd_boolean
diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h
index efa835e104..344cd57c86 100644
--- a/bfd/elfxx-x86.h
+++ b/bfd/elfxx-x86.h
@@ -181,12 +181,12 @@
|| bfd_link_executable (INFO))
/* TRUE if this is a PLT reference to a local IFUNC. */
-#define PLT_LOCAL_IFUNC_P(INFO, H) \
- ((H)->dynindx == -1 \
+#define PLT_LOCAL_IFUNC_P(INFO, EH) \
+ ((EH)->elf.dynindx == -1 \
|| ((bfd_link_executable (INFO) \
- || ELF_ST_VISIBILITY ((H)->other) != STV_DEFAULT) \
- && (H)->def_regular \
- && (H)->type == STT_GNU_IFUNC))
+ || ELF_ST_VISIBILITY ((EH)->elf.other) != STV_DEFAULT) \
+ && (EH)->elf.def_regular \
+ && (EH)->type == STT_GNU_IFUNC))
/* TRUE if TLS IE->LE transition is OK. */
#define TLS_TRANSITION_IE_TO_LE_P(INFO, H, TLS_TYPE) \
@@ -235,6 +235,9 @@ struct elf_x86_link_hash_entry
unsigned char tls_type;
+ /* Original symbol type (STT_NOTYPE, STT_OBJECT, etc.). */
+ unsigned int type : 8;
+
/* Bit 0: Symbol has no GOT nor PLT relocations.
Bit 1: Symbol has non-GOT/non-PLT relocations in text sections.
zero_undefweak is initialized to 1 and undefined weak symbol
@@ -674,6 +677,10 @@ extern bfd_boolean _bfd_x86_elf_merge_gnu_properties
extern bfd * _bfd_x86_elf_link_setup_gnu_properties
(struct bfd_link_info *, struct elf_x86_init_table *);
+extern void _bfd_x86_elf_link_fixup_ifunc_symbol
+ (struct bfd_link_info *, struct elf_x86_link_hash_table *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *sym);
+
#define bfd_elf64_mkobject \
_bfd_x86_elf_mkobject
#define bfd_elf32_mkobject \
diff --git a/ld/testsuite/ld-ifunc/ifunc-9-i386.d b/ld/testsuite/ld-ifunc/ifunc-9-i386.d
new file mode 100644
index 0000000000..754ee2deca
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/ifunc-9-i386.d
@@ -0,0 +1,9 @@
+#source: ifunc-9-x86.s
+#as: --32
+#ld: -m elf_i386 --export-dynamic
+#readelf: -r --wide
+#target: x86_64-*-* i?86-*-*
+
+Relocation section '.rel.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*
diff --git a/ld/testsuite/ld-ifunc/ifunc-9-x86-64.d b/ld/testsuite/ld-ifunc/ifunc-9-x86-64.d
new file mode 100644
index 0000000000..85c3a69150
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/ifunc-9-x86-64.d
@@ -0,0 +1,9 @@
+#source: ifunc-9-x86.s
+#as: --64
+#ld: -melf_x86_64 --export-dynamic
+#readelf: -r --wide
+#target: x86_64-*-*
+
+Relocation section '.rela.plt' at .*
+[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
+[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*
diff --git a/ld/testsuite/ld-ifunc/ifunc-9-x86.d b/ld/testsuite/ld-ifunc/ifunc-9-x86.d
deleted file mode 100644
index 7390dd1fed..0000000000
--- a/ld/testsuite/ld-ifunc/ifunc-9-x86.d
+++ /dev/null
@@ -1,3 +0,0 @@
-#ld: --export-dynamic
-#error: .*dynamic STT_GNU_IFUNC symbol `foo' with pointer equality in `.*.o' can not be used when making an executable; recompile with -fPIE and relink with -pie
-#target: x86_64-*-* i?86-*-*
diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp
index d9cc381e44..7503a98370 100644
--- a/ld/testsuite/ld-ifunc/ifunc.exp
+++ b/ld/testsuite/ld-ifunc/ifunc.exp
@@ -581,6 +581,32 @@ run_cc_link_tests [list \
{} \
"libpr18841cn.so" \
] \
+ [list \
+ "Build libpr23169.so" \
+ "-shared" \
+ "-fPIC -O2 -g" \
+ { pr23169a.c } \
+ {} \
+ "libpr23169.so" \
+ ] \
+ [list \
+ "Build pr23169a" \
+ "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169.so" \
+ "$NOPIE_CFLAGS -O2 -g" \
+ { pr23169b.c pr23169c.c } \
+ {{readelf {--dyn-syms} pr23169a.rd} \
+ {readelf {-r -W} pr23169b.rd}} \
+ "pr23169a" \
+ ] \
+ [list \
+ "Build pr23169b" \
+ "-pie -Wl,--no-as-needed tmpdir/libpr23169.so" \
+ "-fPIE -O2 -g" \
+ { pr23169b.c pr23169c.c } \
+ {{readelf {--dyn-syms} pr23169c.rd} \
+ {readelf {-r -W} pr23169b.rd}} \
+ "pr23169b" \
+ ] \
]
run_ld_link_exec_tests [list \
@@ -632,4 +658,22 @@ run_ld_link_exec_tests [list \
"pr18841cn" \
"pr18841.out" \
] \
+ [list \
+ "Run pr23169a" \
+ "$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169.so" \
+ "" \
+ { pr23169b.c pr23169c.c } \
+ "pr23169a" \
+ "pass.out" \
+ "$NOPIE_CFLAGS -O2 -g" \
+ ] \
+ [list \
+ "Run pr23169b" \
+ "-pie -Wl,--no-as-needed tmpdir/libpr23169.so" \
+ "" \
+ { pr23169b.c pr23169c.c } \
+ "pr23169b" \
+ "pass.out" \
+ "-fPIE -O2 -g" \
+ ] \
]
diff --git a/ld/testsuite/ld-ifunc/pr23169a.c b/ld/testsuite/ld-ifunc/pr23169a.c
new file mode 100644
index 0000000000..02bf220890
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169a.c
@@ -0,0 +1,9 @@
+int (*func_p) (void);
+extern int func (void);
+
+void
+foo (void)
+{
+ if (func_p != &func || func_p () != 0xbadbeef)
+ __builtin_abort ();
+}
diff --git a/ld/testsuite/ld-ifunc/pr23169a.rd b/ld/testsuite/ld-ifunc/pr23169a.rd
new file mode 100644
index 0000000000..ca04d8fc38
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169a.rd
@@ -0,0 +1,6 @@
+
+Symbol table '\.dynsym' contains [0-9]+ entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+#...
+ +[0-9]+: +[a-f0-9]+ +0 +FUNC +GLOBAL +DEFAULT +[0-9]+ +func
+#...
diff --git a/ld/testsuite/ld-ifunc/pr23169b.c b/ld/testsuite/ld-ifunc/pr23169b.c
new file mode 100644
index 0000000000..99790d4547
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169b.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+
+extern int (*func_p) (void);
+extern int func (void);
+extern void foo (void);
+
+
+void
+bar (void)
+{
+ if (func_p != &func || func_p () != 0xbadbeef)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ func_p = &func;
+ foo ();
+ bar ();
+ printf ("PASS\n");
+ return 0;
+}
diff --git a/ld/testsuite/ld-ifunc/pr23169b.rd b/ld/testsuite/ld-ifunc/pr23169b.rd
new file mode 100644
index 0000000000..d57a79308b
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169b.rd
@@ -0,0 +1,3 @@
+#failif
+[a-f0-9]+ +[0-9a-f]+ +R_.*_* +[a-f0-9]+ +func(| \+ 0)
+...
diff --git a/ld/testsuite/ld-ifunc/pr23169c.c b/ld/testsuite/ld-ifunc/pr23169c.c
new file mode 100644
index 0000000000..b530108213
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169c.c
@@ -0,0 +1,13 @@
+static int
+ifunc (void)
+{
+ return 0xbadbeef;
+}
+
+void func(void) __attribute__((ifunc("resolve_func")));
+
+static void *
+resolve_func (void)
+{
+ return ifunc;
+}
diff --git a/ld/testsuite/ld-ifunc/pr23169c.rd b/ld/testsuite/ld-ifunc/pr23169c.rd
new file mode 100644
index 0000000000..1c4ba8ad4a
--- /dev/null
+++ b/ld/testsuite/ld-ifunc/pr23169c.rd
@@ -0,0 +1,6 @@
+
+Symbol table '\.dynsym' contains [0-9]+ entries:
+ +Num: +Value +Size Type +Bind +Vis +Ndx Name
+#...
+ +[0-9]+: +[a-f0-9]+ +[0-9]+ +IFUNC +GLOBAL +DEFAULT +[0-9]+ +func
+#...
--
2.17.0
More information about the Binutils
mailing list