This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: PATCH: Support STT_GNU_IFUNC in executables
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: "H.J. Lu" <hjl dot tools at gmail dot com>
- Cc: GNU C Library <libc-alpha at sourceware dot org>
- Date: Tue, 26 May 2009 14:41:46 -0700
- Subject: Re: PATCH: Support STT_GNU_IFUNC in executables
- References: <20090526211120.GA30522@lucon.org>
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
On Tue, May 26, 2009 at 02:11:20PM -0700, H.J. Lu wrote:
> Hi,
>
> We have STT_GNU_IFUNC symbol definitions in executables, which leads
> to DT_TEXTREL. We need to turn on PROT_EXEC during relocation.
>
>
"loader" may be NULL when ld.so is run directly. Here is the
updated patch.
H.J.
2009-05-26 H.J. Lu <hongjiu.lu@intel.com>
* elf/dl-load.c (open_verify): Set the l_ifunc field.
* elf/dl-reloc.c (_dl_relocate_object): Add PROT_EXEC for
DT_TEXTREL if l_ifunc is TRUE.
* include/link.h (link_map): Add l_ifunc.
* sysdeps/unix/sysv/linux/ldsodefs.h (HAVE_STT_GNU_IFUNC): New.
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 0b896d9..f0d593c 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1737,6 +1737,11 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
}
}
+#ifdef HAVE_STT_GNU_IFUNC
+ if (__builtin_expect (loader, 1))
+ loader->l_ifunc = HAVE_STT_GNU_IFUNC (ehdr);
+#endif
+
/* Check .note.ABI-tag if present. */
for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
index 28f08de..8b7484f 100644
--- a/elf/dl-reloc.c
+++ b/elf/dl-reloc.c
@@ -200,6 +200,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
if (ph->p_type == PT_LOAD && (ph->p_flags & PF_W) == 0)
{
struct textrels *newp;
+ int prot;
newp = (struct textrels *) alloca (sizeof (*newp));
newp->len = (((ph->p_vaddr + ph->p_memsz + GLRO(dl_pagesize) - 1)
@@ -208,7 +209,13 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
newp->start = ((ph->p_vaddr & ~(GLRO(dl_pagesize) - 1))
+ (caddr_t) l->l_addr);
- if (__mprotect (newp->start, newp->len, PROT_READ|PROT_WRITE) < 0)
+ /* We need PROT_EXEC for STT_GNU_IFUNC. */
+ if (__builtin_expect(l->l_ifunc, 0))
+ prot = PROT_READ|PROT_WRITE|PROT_EXEC;
+ else
+ prot = PROT_READ|PROT_WRITE;
+
+ if (__mprotect (newp->start, newp->len, prot) < 0)
{
errstring = N_("cannot make segment writable for relocation");
call_error:
diff --git a/include/link.h b/include/link.h
index 4b9978a..1281c12 100644
--- a/include/link.h
+++ b/include/link.h
@@ -189,6 +189,7 @@ struct link_map
unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are
mprotected or if no holes are present at
all. */
+ unsigned int l_ifunc:1; /* Nonzero if object has STT_GNU_IFUNC. */
/* Collected information about own RPATH directories. */
struct r_search_path_struct l_rpath_dirs;
diff --git a/sysdeps/unix/sysv/linux/ldsodefs.h b/sysdeps/unix/sysv/linux/ldsodefs.h
index 0965f14..c67a501 100644
--- a/sysdeps/unix/sysv/linux/ldsodefs.h
+++ b/sysdeps/unix/sysv/linux/ldsodefs.h
@@ -73,4 +73,7 @@ extern void _dl_non_dynamic_init (void) internal_function;
[EI_ABIVERSION] = 0 \
}
+#define HAVE_STT_GNU_IFUNC(ehdr) \
+ ((ehdr)->e_ident[EI_OSABI] == ELFOSABI_LINUX)
+
#endif /* ldsodefs.h */