If PIE (position-independent executables) are supported, build valgrind's
stage2 as one. This means that we're not hard-wiring stage2 in at 0xb0000000,
which means our memory layout is a bit more flexible, yay.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2833 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/configure.in b/configure.in
index 7372085..ff8707d 100644
--- a/configure.in
+++ b/configure.in
@@ -370,6 +370,23 @@
AC_SUBST(PREFERRED_STACK_BOUNDARY)
+# Check for PIE support in the compiler and linker
+AC_CACHE_CHECK([for PIE support], vg_cv_pie,
+ [safe_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -fpie"
+ safe_LDFLAGS=$LDFLAGS
+ LDFLAGS="$LDFLAGS -pie"
+ AC_TRY_LINK([int foo;],
+ [],
+ [vg_cv_pie=yes],
+ [vg_cv_pie=no])
+ CFLAGS=$safe_CFLAGS
+ LDFLAGS=$safe_LDFLAGS])
+if test "$vg_cv_pie" = yes; then
+AC_DEFINE([HAVE_PIE], 1, [can create position-independent executables])
+fi
+AM_CONDITIONAL(USE_PIE, test "$vg_cv_pie" = "yes")
+
# Checks for header files.
AC_HEADER_STDC
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index a1a4a17..3c21458 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -77,11 +77,22 @@
vg_toolint.c \
vg_translate.c \
vg_transtab.c
+## Test repeated in both arms of the if-then-else because older versions of
+## automake don't seem to like having += within an if-then-else.
+if USE_PIE
+stage2_CFLAGS = $(AM_CFLAGS) -fpie
+stage2_DEPENDENCIES = $(srcdir)/valgrind.vs
+stage2_LDFLAGS = -Wl,--export-dynamic -g \
+ -Wl,-version-script $(srcdir)/valgrind.vs \
+ -pie
+else
+stage2_CFLAGS = $(AM_CFLAGS)
stage2_DEPENDENCIES = $(srcdir)/valgrind.vs ${VG_ARCH}/stage2.lds
-stage2_LDFLAGS=-Wl,--export-dynamic -g \
- -Wl,-defsym,kickstart_base=@KICKSTART_BASE@ \
- -Wl,-T,${VG_ARCH}/stage2.lds \
- -Wl,-version-script $(srcdir)/valgrind.vs
+stage2_LDFLAGS = -Wl,--export-dynamic -g \
+ -Wl,-version-script $(srcdir)/valgrind.vs \
+ -Wl,-defsym,kickstart_base=@KICKSTART_BASE@ -Wl,-T,${VG_ARCH}/stage2.lds
+endif
+
stage2_LDADD= \
demangle/cp-demangle.o \
demangle/cplus-dem.o \
diff --git a/coregrind/demangle/Makefile.am b/coregrind/demangle/Makefile.am
index 48cb752..68040fe 100644
--- a/coregrind/demangle/Makefile.am
+++ b/coregrind/demangle/Makefile.am
@@ -1,7 +1,13 @@
include $(top_srcdir)/Makefile.all.am
include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am
+## Test repeated in both arms of the if-then-else because older versions of
+## automake don't seem to like having += within an if-then-else.
+if USE_PIE
+AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -g -fpie
+else
AM_CFLAGS = $(WERROR) -Winline -Wall -Wshadow -O -g
+endif
noinst_HEADERS = \
ansidecl.h \
diff --git a/coregrind/stage1.c b/coregrind/stage1.c
index 0c4e030..9d66d20 100644
--- a/coregrind/stage1.c
+++ b/coregrind/stage1.c
@@ -259,16 +259,19 @@
int *esp;
char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
+#ifdef HAVE_PIE
+ info.exe_base = ROUNDDN(info.exe_end - 0x02000000, 0x10000000);
+ assert(info.exe_base >= PGROUNDUP(&_end));
+ info.map_base = info.exe_base + 0x01000000;
+#else
+
+ // If this system doesn't have PIE (position-independent executables),
+ // we have to choose a hardwired location for stage2.
info.exe_base = PGROUNDUP(&_end);
+ info.map_base = KICKSTART_BASE + 0x01000000;
+#endif
info.exe_end = PGROUNDDN(init_sp);
- /* XXX FIXME: how can stage1 know where stage2 wants things placed?
- Options:
- - we could look for a symbol
- - it could have a special PHDR (v. ELF specific)
- - something else?
- */
- info.map_base = KICKSTART_BASE + 0x01000000;
info.argv = NULL;
snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
diff --git a/coregrind/ume.c b/coregrind/ume.c
index 7fe3146..17f012b 100644
--- a/coregrind/ume.c
+++ b/coregrind/ume.c
@@ -281,13 +281,18 @@
{
struct elfinfo *e;
struct elfinfo *interp = NULL;
- ESZ(Addr) exeoff = 0; /* offset between link address and load address */
ESZ(Addr) minaddr = ~0; /* lowest mapped address */
ESZ(Addr) maxaddr = 0; /* highest mapped address */
ESZ(Addr) interp_addr = 0; /* interpreter (ld.so) address */
ESZ(Word) interp_size = 0; /* interpreter size */
+ ESZ(Word) interp_align = VKI_BYTES_PER_PAGE;
int i;
void *entry;
+ ESZ(Addr) ebase = 0;
+
+#ifdef HAVE_PIE
+ ebase = info->exe_base;
+#endif
e = readelf(fd, name);
@@ -295,14 +300,14 @@
return ENOEXEC;
info->phnum = e->e.e_phnum;
- info->entry = e->e.e_entry;
+ info->entry = e->e.e_entry + ebase;
for(i = 0; i < e->e.e_phnum; i++) {
ESZ(Phdr) *ph = &e->p[i];
switch(ph->p_type) {
case PT_PHDR:
- info->phdr = ph->p_vaddr;
+ info->phdr = ph->p_vaddr + ebase;
break;
case PT_LOAD:
@@ -344,7 +349,8 @@
continue;
if (!baseaddr_set) {
- interp_addr = iph->p_vaddr;
+ interp_addr = iph->p_vaddr;
+ interp_align = iph->p_align;
baseaddr_set = 1;
}
@@ -363,29 +369,19 @@
}
}
- if (e->e.e_type == ET_DYN) {
- /* PIE executable */
- exeoff = info->exe_base - minaddr;
- }
-
- minaddr += exeoff;
- maxaddr += exeoff;
- info->phdr += exeoff;
- info->entry += exeoff;
-
if (info->exe_base != info->exe_end) {
if (minaddr >= maxaddr ||
- (minaddr < info->exe_base ||
- maxaddr > info->exe_end)) {
+ (minaddr + ebase < info->exe_base ||
+ maxaddr + ebase > info->exe_end)) {
fprintf(stderr, "Executable range %p-%p is outside the\n"
"acceptable range %p-%p\n",
- (void *)minaddr, (void *)maxaddr,
- (void *)info->exe_base, (void *)info->exe_end);
+ (void *)minaddr + ebase, (void *)maxaddr + ebase,
+ (void *)info->exe_base, (void *)info->exe_end);
return ENOMEM;
}
}
- info->brkbase = mapelf(e, exeoff); /* map the executable */
+ info->brkbase = mapelf(e, ebase); /* map the executable */
if (info->brkbase == 0)
return ENOMEM;
@@ -398,7 +394,7 @@
int flags = MAP_PRIVATE|MAP_ANONYMOUS;
if (info->map_base != 0) {
- base = (char *)info->map_base;
+ base = (char *)ROUNDUP(info->map_base, interp_align);
flags |= MAP_FIXED;
}
@@ -417,10 +413,10 @@
free(interp);
} else
- entry = (void *)e->e.e_entry + exeoff;
+ entry = (void *)e->e.e_entry;
- info->exe_base = minaddr;
- info->exe_end = maxaddr;
+ info->exe_base = minaddr + ebase;
+ info->exe_end = maxaddr + ebase;
info->init_eip = (addr_t)entry;
diff --git a/coregrind/vg_main.c b/coregrind/vg_main.c
index 7076d62..4535c7b 100644
--- a/coregrind/vg_main.c
+++ b/coregrind/vg_main.c
@@ -85,8 +85,6 @@
/* ---------------------------------------------------------------------
Startup stuff
------------------------------------------------------------------ */
-/* linker-defined base address */
-extern char kickstart_base;
/* Client address space, lowest to highest (see top of ume.c) */
Addr VG_(client_base); /* client address space limits */
@@ -378,6 +376,10 @@
vgexecfd = auxv->u.a_val;
found |= 2;
break;
+
+ case AT_PHDR:
+ VG_(valgrind_base) = PGROUNDDN(auxv->u.a_val);
+ break;
}
if ( found != (1|2) ) {
@@ -393,13 +395,21 @@
/*=== Address space determination ===*/
/*====================================================================*/
+extern char _start[];
+
static void layout_remaining_space(Addr argc_addr, float ratio)
{
Int ires;
void* vres;
addr_t client_size, shadow_size;
- VG_(valgrind_base) = (addr_t)&kickstart_base;
+ // VG_(valgrind_base) should have been set by scan_auxv, but if not,
+ // this is a workable approximation
+ if (VG_(valgrind_base) == 0) {
+ OINK(1);
+ VG_(valgrind_base) = PGROUNDDN(&_start);
+ }
+
VG_(valgrind_last) = ROUNDUP(argc_addr, 0x10000) - 1; // stack
// This gives the client the largest possible address space while