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