summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorAndreas Schwab <aschwab@redhat.com>2009-06-10 14:04:22 +0200
committerAndreas Schwab <aschwab@redhat.com>2009-06-10 14:04:22 +0200
commit0d02cb10e8dd8639b86450cf8e597cf5e2e09894 (patch)
tree0f2174db43a501b946f0600d1b91ae4117977b04 /elf
parentdfbbe67270efa9c03f9444d50d2f98a7a64622b4 (diff)
parent88ea382fda5af7717f85bb19837c9c99094f3df4 (diff)
Merge commit 'origin/master' into fedora/master
Conflicts: ChangeLog sysdeps/unix/sysv/linux/i386/sysconf.c sysdeps/x86_64/cacheinfo.c version.h
Diffstat (limited to 'elf')
-rw-r--r--elf/.cvsignore6
-rw-r--r--elf/Makefile106
-rw-r--r--elf/check-execstack.c158
-rw-r--r--elf/dl-sysdep.c2
-rw-r--r--elf/elf.h6
-rw-r--r--elf/ifuncdep1.c3
-rw-r--r--elf/ifuncdep1pic.c3
-rw-r--r--elf/ifuncdep2.c72
-rw-r--r--elf/ifuncdep2pic.c3
-rw-r--r--elf/ifuncmain1.c66
-rw-r--r--elf/ifuncmain1pic.c3
-rw-r--r--elf/ifuncmain1picstatic.c3
-rw-r--r--elf/ifuncmain1pie.c3
-rw-r--r--elf/ifuncmain1static.c3
-rw-r--r--elf/ifuncmain1staticpic.c3
-rw-r--r--elf/ifuncmain1vis.c89
-rw-r--r--elf/ifuncmain1vispic.c3
-rw-r--r--elf/ifuncmain1vispie.c3
-rw-r--r--elf/ifuncmain2.c16
-rw-r--r--elf/ifuncmain2pic.c3
-rw-r--r--elf/ifuncmain2picstatic.c3
-rw-r--r--elf/ifuncmain2static.c3
-rw-r--r--elf/ifuncmain3.c120
-rw-r--r--elf/ifuncmain4.c4
-rw-r--r--elf/ifuncmain4picstatic.c3
-rw-r--r--elf/ifuncmain4static.c3
-rw-r--r--elf/ifuncmod1.c114
-rw-r--r--elf/ifuncmod3.c8
28 files changed, 801 insertions, 11 deletions
diff --git a/elf/.cvsignore b/elf/.cvsignore
deleted file mode 100644
index 3fc9f4cdf1..0000000000
--- a/elf/.cvsignore
+++ /dev/null
@@ -1,6 +0,0 @@
-*.d *.o *.so *.po *.go stamp.* *.stamp *.ustamp *.udeps
-*.gz *.Z *.tar *.tgz
-=*
-TODO COPYING* AUTHORS copyr-* copying.*
-glibc-*
-distinfo
diff --git a/elf/Makefile b/elf/Makefile
index e44ff1d382..6bcbb5142f 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -93,7 +93,16 @@ distribute := rtld-Rules \
order2mod1.c order2mod2.c order2mod3.c order2mod4.c \
tst-stackguard1.c tst-stackguard1-static.c \
tst-array5.c tst-array5-static.c tst-array5dep.c \
- tst-array5.exp tst-leaks1.c
+ tst-array5.exp tst-leaks1.c check-execstack.c \
+ ifuncmain1.c ifuncmain1pic.c ifuncmain1vis.c \
+ ifuncmain1vispic.c ifuncmain1static.c \
+ ifuncmain1staticpic.c ifuncmain1picstatic.c \
+ ifuncdep1.c ifuncdep1pic.c ifuncmod1.c \
+ ifuncmain1pie.c ifuncmain1vispie.c \
+ ifuncmain2.c ifuncmain2static.c ifuncdep2.c \
+ ifuncmain2pic.c ifuncmain2picstatic.c ifuncdep2pic.c \
+ ifuncmain3.c ifuncmod3.c \
+ ifuncmain4.c ifuncmain4static.c ifuncmain4picstatic.c
CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables
CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables
@@ -232,6 +241,22 @@ test-extras += $(modules-names)
# filtmod1.so has a special rule
modules-names-nobuild := filtmod1
+ifeq (yes,$(multi-arch))
+tests-static += ifuncmain1static ifuncmain1picstatic \
+ ifuncmain2static ifuncmain2picstatic \
+ ifuncmain4static ifuncmain4picstatic
+
+ifeq (yes,$(build-shared))
+tests += ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
+ ifuncmain1staticpic \
+ ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4
+ifeq (yes,$(have-fpie))
+tests: $(objpfx)ifuncmain1pie.out $(objpfx)ifuncmain1vispie.out
+endif
+modules-names += ifuncmod1 ifuncmod3
+endif
+endif
+
include ../Rules
@@ -504,6 +529,7 @@ reldep8mod2.so-no-z-defs = yes
reldep9mod1.so-no-z-defs = yes
unload3mod4.so-no-z-defs = yes
unload4mod1.so-no-z-defs = yes
+ifuncmod1.so-no-z-defs = yes
ifeq ($(build-shared),yes)
# Build all the modules even when not actually running test programs.
@@ -842,12 +868,16 @@ check-textrel-CFLAGS = -O -Wall -D_XOPEN_SOURCE=600 -D_BSD_SOURCE
$(objpfx)check-textrel: check-textrel.c
$(native-compile)
+check-execstack-CFLAGS = -O -Wall -D_XOPEN_SOURCE=600 -D_BSD_SOURCE -std=gnu99
+$(objpfx)check-execstack: check-execstack.c
+ $(native-compile)
+
check-localplt-CFLAGS = -O -Wall -D_GNU_SOURCE -std=gnu99
$(objpfx)check-localplt: check-localplt.c
$(native-compile)
ifeq (yes,$(build-shared))
-tests: $(objpfx)check-textrel.out
+tests: $(objpfx)check-textrel.out $(objpfx)check-execstack.out
$(objpfx)check-textrel.out: $(objpfx)check-textrel
$(dir $<)$(notdir $<) $(common-objpfx)libc.so \
@@ -855,6 +885,12 @@ $(objpfx)check-textrel.out: $(objpfx)check-textrel
$(common-objpfx)iconvdata/*.so)) > $@
generated += check-textrel check-textrel.out
+$(objpfx)check-execstack.out: $(objpfx)check-execstack
+ $(dir $<)$(notdir $<) $(common-objpfx)libc.so \
+ $(sort $(wildcard $(common-objpfx)*/lib*.so \
+ $(common-objpfx)iconvdata/*.so)) > $@
+generated += check-execstack check-execstack.out
+
$(objpfx)tst-dlmodcount: $(libdl)
$(objpfx)tst-dlmodcount.out: $(test-modules)
@@ -941,3 +977,69 @@ tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
$(objpfx)tst-addr1: $(libdl)
$(objpfx)tst-thrlock: $(libdl) $(shared-thread-library)
+
+CFLAGS-ifuncmain1pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1staticpic.c += $(pic-ccflag)
+CFLAGS-ifuncdep1pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain1vispic.c += $(pic-ccflag)
+CFLAGS-ifuncmain2pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain2picstatic.c += $(pic-ccflag)
+CFLAGS-ifuncdep2pic.c += $(pic-ccflag)
+CFLAGS-ifuncmain4picstatic.c += $(pic-ccflag)
+
+LDFLAGS-ifuncmain3 = -Wl,-export-dynamic
+
+ifeq (yesyes,$(have-fpie)$(build-shared))
+CFLAGS-ifuncmain1pie.c += $(pie-ccflag)
+CFLAGS-ifuncmain1vispie.c += $(pie-ccflag)
+
+$(objpfx)ifuncmain1pie.out: $(objpfx)ifuncmain1pie
+ $(elf-objpfx)$(rtld-installed-name) \
+ --library-path $(rpath-link)$(patsubst %,:%,$(sysdep-library-path)) \
+ $< > $@
+
+$(objpfx)ifuncmain1pie: $(objpfx)ifuncmain1pie.o $(objpfx)ifuncmod1.so
+ $(LINK.o) -pie -Wl,-O1 \
+ $(sysdep-LDFLAGS) $(config-LDFLAGS) \
+ $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
+ $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
+ $(LDFLAGS) $(LDFLAGS-$(@F)) \
+ -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
+ -o $@ $(objpfx)tst-pie1.o $(objpfx)tst-piemod1.so \
+ $(common-objpfx)libc_nonshared.a
+
+generated += ifuncmain1pie ifuncmain1pie.out
+
+$(objpfx)ifuncmain1vispie.out: $(objpfx)ifuncmain1vispie
+ $(elf-objpfx)$(rtld-installed-name) \
+ --library-path $(rpath-link)$(patsubst %,:%,$(sysdep-library-path)) \
+ $< > $@
+
+$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmain1vispie.o $(objpfx)ifuncmod1.so
+ $(LINK.o) -pie -Wl,-O1 \
+ $(sysdep-LDFLAGS) $(config-LDFLAGS) \
+ $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
+ $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
+ $(LDFLAGS) $(LDFLAGS-$(@F)) \
+ -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) \
+ -o $@ $(objpfx)tst-pie1.o $(objpfx)tst-piemod1.so \
+ $(common-objpfx)libc_nonshared.a
+
+generated += ifuncmain1vispie ifuncmain1vispie.out
+endif
+
+$(objpfx)ifuncmain1: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1pic: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1staticpic: $(addprefix $(objpfx),ifuncdep1pic.o)
+$(objpfx)ifuncmain1static: $(addprefix $(objpfx),ifuncdep1.o)
+$(objpfx)ifuncmain1picstatic: $(addprefix $(objpfx),ifuncdep1pic.o)
+$(objpfx)ifuncmain1vis: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain1vispic: $(addprefix $(objpfx),ifuncmod1.so)
+$(objpfx)ifuncmain2: $(addprefix $(objpfx),ifuncdep2.o)
+$(objpfx)ifuncmain2pic: $(addprefix $(objpfx),ifuncdep2pic.o)
+$(objpfx)ifuncmain2static: $(addprefix $(objpfx),ifuncdep2.o)
+$(objpfx)ifuncmain2picstatic: $(addprefix $(objpfx),ifuncdep2pic.o)
+
+$(objpfx)ifuncmain3: $(libdl)
+$(objpfx)ifuncmain3.out: $(objpfx)ifuncmod3.so
diff --git a/elf/check-execstack.c b/elf/check-execstack.c
new file mode 100644
index 0000000000..55cf48721a
--- /dev/null
+++ b/elf/check-execstack.c
@@ -0,0 +1,158 @@
+/* Check for executable stacks in DSOs.
+ Copyright (C) 2009 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contribute by Ulrich Drepper <drepper@redhat.com>. 2009.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <byteswap.h>
+#include <elf.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#ifdef BITS
+
+# define AB(name) _AB (name, BITS)
+# define _AB(name, bits) __AB (name, bits)
+# define __AB(name, bits) name##bits
+# define E(name) _E (name, BITS)
+# define _E(name, bits) __E (name, bits)
+# define __E(name, bits) Elf##bits##_##name
+# define SWAP(val) \
+ ({ __typeof (val) __res; \
+ if (((ehdr.e_ident[EI_DATA] == ELFDATA2MSB \
+ && BYTE_ORDER == LITTLE_ENDIAN) \
+ || (ehdr.e_ident[EI_DATA] == ELFDATA2LSB \
+ && BYTE_ORDER == BIG_ENDIAN)) \
+ && sizeof (val) != 1) \
+ { \
+ if (sizeof (val) == 2) \
+ __res = bswap_16 (val); \
+ else if (sizeof (val) == 4) \
+ __res = bswap_32 (val); \
+ else \
+ __res = bswap_64 (val); \
+ } \
+ else \
+ __res = (val); \
+ __res; })
+
+
+static int
+AB(handle_file) (const char *fname, int fd)
+{
+ E(Ehdr) ehdr;
+
+ if (pread (fd, &ehdr, sizeof (ehdr), 0) != sizeof (ehdr))
+ {
+ read_error:
+ printf ("%s: read error: %m\n", fname);
+ return 1;
+ }
+
+ const size_t phnum = SWAP (ehdr.e_phnum);
+ const size_t phentsize = SWAP (ehdr.e_phentsize);
+
+ /* Read the program header. */
+ E(Phdr) *phdr = alloca (phentsize * phnum);
+ if (pread (fd, phdr, phentsize * phnum, SWAP (ehdr.e_phoff))
+ != phentsize * phnum)
+ goto read_error;
+
+ /* Search for the PT_GNU_STACK entry. */
+ for (size_t cnt = 0; cnt < phnum; ++cnt)
+ if (SWAP (phdr[cnt].p_type) == PT_GNU_STACK)
+ {
+ unsigned int flags = SWAP(phdr[cnt].p_flags);
+ if (flags & PF_X)
+ {
+ printf ("%s: executable stack signaled\n", fname);
+ return 1;
+ }
+
+ return 0;
+ }
+
+ printf ("%s: no PT_GNU_STACK entry\n", fname);
+ return 1;
+}
+
+# undef BITS
+#else
+
+# define BITS 32
+# include "check-execstack.c"
+
+# define BITS 64
+# include "check-execstack.c"
+
+
+static int
+handle_file (const char *fname)
+{
+ int fd = open (fname, O_RDONLY);
+ if (fd == -1)
+ {
+ printf ("cannot open %s: %m\n", fname);
+ return 1;
+ }
+
+ /* Read was is supposed to be the ELF header. Read the initial
+ bytes to determine whether this is a 32 or 64 bit file. */
+ char ident[EI_NIDENT];
+ if (read (fd, ident, EI_NIDENT) != EI_NIDENT)
+ {
+ printf ("%s: read error: %m\n", fname);
+ close (fd);
+ return 1;
+ }
+
+ if (memcmp (&ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
+ {
+ printf ("%s: not an ELF file\n", fname);
+ close (fd);
+ return 1;
+ }
+
+ int result;
+ if (ident[EI_CLASS] == ELFCLASS64)
+ result = handle_file64 (fname, fd);
+ else
+ result = handle_file32 (fname, fd);
+
+ close (fd);
+
+ return result;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int cnt;
+ int result = 0;
+
+ for (cnt = 1; cnt < argc; ++cnt)
+ result |= handle_file (argv[cnt]);
+
+ return result;
+}
+#endif
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index db1001253c..5700272f10 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -335,7 +335,7 @@ _dl_show_auxv (void)
/* Unknown value: print a generic line. */
char buf2[17];
- buf[sizeof (buf2) - 1] = '\0';
+ buf2[sizeof (buf2) - 1] = '\0';
const char *val2 = _itoa ((unsigned long int) av->a_un.a_val,
buf2 + sizeof buf2 - 1, 16, 0);
const char *val = _itoa ((unsigned long int) av->a_type,
diff --git a/elf/elf.h b/elf/elf.h
index 062ef00f57..8fdf74b099 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1177,8 +1177,9 @@ typedef struct
pointer to code and to
argument, returning the TLS
offset for the symbol. */
+#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
/* Keep this the last entry. */
-#define R_386_NUM 42
+#define R_386_NUM 43
/* SUN SPARC specific definitions. */
@@ -2625,8 +2626,9 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
descriptor. */
#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
-#define R_X86_64_NUM 37
+#define R_X86_64_NUM 38
/* AM33 relocations. */
diff --git a/elf/ifuncdep1.c b/elf/ifuncdep1.c
new file mode 100644
index 0000000000..77d663dcec
--- /dev/null
+++ b/elf/ifuncdep1.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols without -fPIC. */
+
+#include "ifuncmod1.c"
diff --git a/elf/ifuncdep1pic.c b/elf/ifuncdep1pic.c
new file mode 100644
index 0000000000..b6381e4868
--- /dev/null
+++ b/elf/ifuncdep1pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmod1.c"
diff --git a/elf/ifuncdep2.c b/elf/ifuncdep2.c
new file mode 100644
index 0000000000..fb21eef5cb
--- /dev/null
+++ b/elf/ifuncdep2.c
@@ -0,0 +1,72 @@
+/* Test 3 STT_GNU_IFUNC symbols. */
+
+extern int global;
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo1_ifunc (void) __asm__ ("foo1");
+__asm__(".type foo1, %gnu_indirect_function");
+
+void *
+foo1_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return one;
+ case -1:
+ return minus_one;
+ default:
+ return zero;
+ }
+}
+
+void * foo2_ifunc (void) __asm__ ("foo2");
+__asm__(".type foo2, %gnu_indirect_function");
+
+void *
+foo2_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return minus_one;
+ case -1:
+ return one;
+ default:
+ return zero;
+ }
+}
+
+void * foo3_ifunc (void) __asm__ ("foo3");
+__asm__(".type foo3, %gnu_indirect_function");
+
+void *
+foo3_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return one;
+ case -1:
+ return zero;
+ default:
+ return minus_one;
+ }
+}
diff --git a/elf/ifuncdep2pic.c b/elf/ifuncdep2pic.c
new file mode 100644
index 0000000000..a84253dbc4
--- /dev/null
+++ b/elf/ifuncdep2pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncdep2.c"
diff --git a/elf/ifuncmain1.c b/elf/ifuncmain1.c
new file mode 100644
index 0000000000..de7ffe8779
--- /dev/null
+++ b/elf/ifuncmain1.c
@@ -0,0 +1,66 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility without override.
+ */
+
+#include <stdlib.h>
+
+int global = -1;
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if (foo () != -1)
+ abort ();
+ if ((*foo_ptr) () != -1)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if (foo_protected () != 0)
+ abort ();
+ if ((*foo_procted_ptr) () != 0)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (ret_foo != -1 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p != foo_protected)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/elf/ifuncmain1pic.c b/elf/ifuncmain1pic.c
new file mode 100644
index 0000000000..db19dc9678
--- /dev/null
+++ b/elf/ifuncmain1pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain1picstatic.c b/elf/ifuncmain1picstatic.c
new file mode 100644
index 0000000000..c937933029
--- /dev/null
+++ b/elf/ifuncmain1picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain1pie.c b/elf/ifuncmain1pie.c
new file mode 100644
index 0000000000..c16ef6dd09
--- /dev/null
+++ b/elf/ifuncmain1pie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE. */
+
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain1static.c b/elf/ifuncmain1static.c
new file mode 100644
index 0000000000..fdd1e09024
--- /dev/null
+++ b/elf/ifuncmain1static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain1staticpic.c b/elf/ifuncmain1staticpic.c
new file mode 100644
index 0000000000..39e0cbb4b8
--- /dev/null
+++ b/elf/ifuncmain1staticpic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and no DSO. */
+
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain1vis.c b/elf/ifuncmain1vis.c
new file mode 100644
index 0000000000..a239d2dd0d
--- /dev/null
+++ b/elf/ifuncmain1vis.c
@@ -0,0 +1,89 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <stdlib.h>
+
+int global = -1;
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+
+extern int foo (void);
+extern int foo_protected (void);
+
+#ifndef FOO_P
+typedef int (*foo_p) (void);
+#endif
+
+foo_p foo_ptr = foo;
+foo_p foo_procted_ptr = foo_protected;
+
+extern foo_p get_foo_p (void);
+extern foo_p get_foo_hidden_p (void);
+extern foo_p get_foo_protected_p (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+
+ if (foo_ptr != foo)
+ abort ();
+ if ((*foo_ptr) () != -30)
+ abort ();
+
+ if (foo_procted_ptr != foo_protected)
+ abort ();
+ if ((*foo_procted_ptr) () != -40)
+ abort ();
+
+ p = get_foo_p ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (ret_foo != -30 || (*p) () != ret_foo)
+ abort ();
+
+ p = get_foo_hidden_p ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (ret_foo_hidden != 1 || (*p) () != ret_foo_hidden)
+ abort ();
+
+ p = get_foo_protected_p ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (ret_foo_protected != 0 || (*p) () != ret_foo_protected)
+ abort ();
+
+ return 0;
+}
diff --git a/elf/ifuncmain1vispic.c b/elf/ifuncmain1vispic.c
new file mode 100644
index 0000000000..f8c104d560
--- /dev/null
+++ b/elf/ifuncmain1vispic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain1vis.c"
diff --git a/elf/ifuncmain1vispie.c b/elf/ifuncmain1vispie.c
new file mode 100644
index 0000000000..ad06d2ba1c
--- /dev/null
+++ b/elf/ifuncmain1vispie.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with PIE. */
+
+#include "ifuncmain1vis.c"
diff --git a/elf/ifuncmain2.c b/elf/ifuncmain2.c
new file mode 100644
index 0000000000..cd9b2c8352
--- /dev/null
+++ b/elf/ifuncmain2.c
@@ -0,0 +1,16 @@
+/* Test calling one STT_GNU_IFUNC function with 3 different
+ STT_GNU_IFUNC definitions. */
+
+#include <stdlib.h>
+
+int global = -1;
+
+extern int foo1 (void);
+
+int
+main (void)
+{
+ if (foo1 () != -1)
+ abort ();
+ return 0;
+}
diff --git a/elf/ifuncmain2pic.c b/elf/ifuncmain2pic.c
new file mode 100644
index 0000000000..0006012a96
--- /dev/null
+++ b/elf/ifuncmain2pic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC. */
+
+#include "ifuncmain2.c"
diff --git a/elf/ifuncmain2picstatic.c b/elf/ifuncmain2picstatic.c
new file mode 100644
index 0000000000..3e89db536d
--- /dev/null
+++ b/elf/ifuncmain2picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain2.c"
diff --git a/elf/ifuncmain2static.c b/elf/ifuncmain2static.c
new file mode 100644
index 0000000000..6932ae8066
--- /dev/null
+++ b/elf/ifuncmain2static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain2.c"
diff --git a/elf/ifuncmain3.c b/elf/ifuncmain3.c
new file mode 100644
index 0000000000..5d067cced9
--- /dev/null
+++ b/elf/ifuncmain3.c
@@ -0,0 +1,120 @@
+/* Test STT_GNU_IFUNC symbols with dlopen:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility with override.
+ */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef int (*foo_p) (void);
+
+int
+__attribute__ ((noinline))
+foo (void)
+{
+ return -30;
+}
+
+int
+__attribute__ ((noinline))
+foo_hidden (void)
+{
+ return -20;
+}
+
+int
+__attribute__ ((noinline))
+foo_protected (void)
+{
+ return -40;
+}
+
+int
+main (void)
+{
+ foo_p p;
+ foo_p (*f) (void);
+ int *ret;
+
+ void *h = dlopen ("ifuncmod3.so", RTLD_LAZY);
+ if (h == NULL)
+ {
+ printf ("cannot load: %s\n", dlerror ());
+ return 1;
+ }
+
+ f = dlsym (h, "get_foo_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p != foo)
+ abort ();
+ if (foo () != -30)
+ abort ();
+ if (*ret != -30 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_hidden_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_hidden");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (foo_hidden () != -20)
+ abort ();
+ if (*ret != 1 || (*p) () != *ret)
+ abort ();
+
+ f = dlsym (h, "get_foo_protected_p");
+ if (f == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ ret = dlsym (h, "ret_foo_protected");
+ if (ret == NULL)
+ {
+ printf ("symbol not found: %s\n", dlerror ());
+ return 1;
+ }
+
+ p = (*f) ();
+ if (p == foo_protected)
+ abort ();
+ if (foo_protected () != -40)
+ abort ();
+ if (*ret != 0 || (*p) () != *ret)
+ abort ();
+
+ if (dlclose (h) != 0)
+ {
+ printf ("cannot close: %s\n", dlerror ());
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/elf/ifuncmain4.c b/elf/ifuncmain4.c
new file mode 100644
index 0000000000..e55fee2eb3
--- /dev/null
+++ b/elf/ifuncmain4.c
@@ -0,0 +1,4 @@
+/* Test STT_GNU_IFUNC symbols in a single source file. */
+
+#include "ifuncmod1.c"
+#include "ifuncmain1.c"
diff --git a/elf/ifuncmain4picstatic.c b/elf/ifuncmain4picstatic.c
new file mode 100644
index 0000000000..977d7f97fc
--- /dev/null
+++ b/elf/ifuncmain4picstatic.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -fPIC and -static. */
+
+#include "ifuncmain4.c"
diff --git a/elf/ifuncmain4static.c b/elf/ifuncmain4static.c
new file mode 100644
index 0000000000..c399977013
--- /dev/null
+++ b/elf/ifuncmain4static.c
@@ -0,0 +1,3 @@
+/* Test STT_GNU_IFUNC symbols with -static. */
+
+#include "ifuncmain4.c"
diff --git a/elf/ifuncmod1.c b/elf/ifuncmod1.c
new file mode 100644
index 0000000000..a1697b596d
--- /dev/null
+++ b/elf/ifuncmod1.c
@@ -0,0 +1,114 @@
+/* Test STT_GNU_IFUNC symbols:
+
+ 1. Direct function call.
+ 2. Function pointer.
+ 3. Visibility.
+ */
+
+extern int global;
+
+static int
+one (void)
+{
+ return 1;
+}
+
+static int
+minus_one (void)
+{
+ return -1;
+}
+
+static int
+zero (void)
+{
+ return 0;
+}
+
+void * foo_ifunc (void) __asm__ ("foo");
+__asm__(".type foo, %gnu_indirect_function");
+
+void *
+foo_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return one;
+ case -1:
+ return minus_one;
+ default:
+ return zero;
+ }
+}
+
+void * foo_hidden_ifunc (void) __asm__ ("foo_hidden");
+__asm__(".type foo_hidden, %gnu_indirect_function");
+
+void *
+foo_hidden_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return minus_one;
+ case -1:
+ return one;
+ default:
+ return zero;
+ }
+}
+
+void * foo_protected_ifunc (void) __asm__ ("foo_protected");
+__asm__(".type foo_protected, %gnu_indirect_function");
+
+void *
+foo_protected_ifunc (void)
+{
+ switch (global)
+ {
+ case 1:
+ return one;
+ case -1:
+ return zero;
+ default:
+ return minus_one;
+ }
+}
+
+/* Test hidden indirect function. */
+__asm__(".hidden foo_hidden");
+
+/* Test protected indirect function. */
+__asm__(".protected foo_protected");
+
+extern int foo (void);
+extern int foo_hidden (void);
+extern int foo_protected (void);
+extern int ret_foo;
+extern int ret_foo_hidden;
+extern int ret_foo_protected;
+
+#define FOO_P
+typedef int (*foo_p) (void);
+
+foo_p
+get_foo_p (void)
+{
+ ret_foo = foo ();
+ return foo;
+}
+
+foo_p
+get_foo_hidden_p (void)
+{
+ ret_foo_hidden = foo_hidden ();
+ return foo_hidden;
+}
+
+foo_p
+get_foo_protected_p (void)
+{
+ ret_foo_protected = foo_protected ();
+ return foo_protected;
+}
diff --git a/elf/ifuncmod3.c b/elf/ifuncmod3.c
new file mode 100644
index 0000000000..379d2c8d53
--- /dev/null
+++ b/elf/ifuncmod3.c
@@ -0,0 +1,8 @@
+/* Test STT_GNU_IFUNC symbols with dlopen. */
+
+#include "ifuncmod1.c"
+
+int ret_foo;
+int ret_foo_hidden;
+int ret_foo_protected;
+int global = -1;