about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/unix/sysv/linux/dl-sysdep.c25
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h6
2 files changed, 30 insertions, 1 deletions
diff --git a/sysdeps/unix/sysv/linux/dl-sysdep.c b/sysdeps/unix/sysv/linux/dl-sysdep.c
index b58f4c13e2..79f95df0a2 100644
--- a/sysdeps/unix/sysv/linux/dl-sysdep.c
+++ b/sysdeps/unix/sysv/linux/dl-sysdep.c
@@ -1,5 +1,5 @@
 /* Dynamic linker system dependencies for Linux.
-   Copyright (C) 1995, 1997, 2001 Free Software Foundation, Inc.
+   Copyright (C) 1995, 1997, 2001, 2004 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -21,6 +21,8 @@
    the generic dynamic linker system interface code.  */
 
 #include <unistd.h>
+#include <ldsodefs.h>
+#include "kernel-features.h"
 
 #define DL_SYSDEP_INIT frob_brk ()
 
@@ -28,6 +30,27 @@ static inline void
 frob_brk (void)
 {
   __brk (0);			/* Initialize the break.  */
+
+#if ! __ASSUME_BRK_PAGE_ROUNDED
+  /* If the dynamic linker was executed as a program, then the break may
+     start immediately after our data segment.  However, dl-minimal.c has
+     already stolen the remainder of the page for internal allocations.
+     If we don't adjust the break location recorded by the kernel, the
+     normal program startup will inquire, find the value at our &_end,
+     and start allocating its own data there, clobbering dynamic linker
+     data structures allocated there during startup.
+
+     Later Linux kernels have changed this behavior so that the initial
+     break value is rounded up to the page boundary before we start.  */
+
+  extern void *__curbrk attribute_hidden;
+  extern void _end attribute_hidden;
+  void *const endpage = (void *) 0 + (((__curbrk - (void *) 0)
+				       + GLRO(dl_pagesize) - 1)
+				      & -GLRO(dl_pagesize));
+  if (__builtin_expect (__curbrk >= &_end && __curbrk < endpage, 0))
+    __brk (endpage);
+#endif
 }
 
 #include <sysdeps/generic/dl-sysdep.c>
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index ee089d550b..6f19fc6360 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -400,3 +400,9 @@
 #if __LINUX_KERNEL_VERSION >= 132612
 # define __ASSUME_GETDENTS32_D_TYPE	1
 #endif
+
+/* Starting with version 2.5.3, the initial location returned by `brk'
+   after exec is always rounded up to the next page.  */
+#if __LINUX_KERNEL_VERSION >= 132355
+# define __ASSUME_BRK_PAGE_ROUNDED	1
+#endif