summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ld/ChangeLog14
-rw-r--r--ld/config.in6
-rwxr-xr-xld/configure182
-rw-r--r--ld/configure.ac3
-rw-r--r--ld/plugin.c89
5 files changed, 275 insertions, 19 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 4ae174b29b0..e838ac853e0 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,17 @@
+2015-02-06 H.J. Lu <hongjiu.lu@intel.com>
+
+ * configure.ac: Add AC_FUNC_MMAP.
+ * config.in: Regenerated.
+ * configure: Likewise.
+ * plugin.c: Include <sys/mman.h>.
+ (MAP_FAILED): New. Defined if not defined.
+ (PROT_READ): Likewise.
+ (MAP_PRIVATE): Likewise.
+ (view_buffer_t): New.
+ (plugin_input_file_t): Add view_buffer.
+ (get_view): Try mmap and cache the view buffer.
+ (plugin_maybe_claim): Initialize view_buffer.
+
2015-02-05 H.J. Lu <hongjiu.lu@intel.com>
* plugin.c (release_input_file): Set fd to -1 after closing it.
diff --git a/ld/config.in b/ld/config.in
index 2ab48448763..ad015fe1a16 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -56,6 +56,9 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
+/* Define to 1 if you have the `getpagesize' function. */
+#undef HAVE_GETPAGESIZE
+
/* Define to 1 if you have the `glob' function. */
#undef HAVE_GLOB
@@ -83,6 +86,9 @@
/* Define to 1 if you have the `mkstemp' function. */
#undef HAVE_MKSTEMP
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#undef HAVE_NDIR_H
diff --git a/ld/configure b/ld/configure
index 8a7bd207c53..7af2626d5bc 100755
--- a/ld/configure
+++ b/ld/configure
@@ -16549,6 +16549,188 @@ fi
fi
+for ac_header in stdlib.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+for ac_func in getpagesize
+do :
+ ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize"
+if test "x$ac_cv_func_getpagesize" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETPAGESIZE 1
+_ACEOF
+
+fi
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5
+$as_echo_n "checking for working mmap... " >&6; }
+if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ ac_cv_func_mmap_fixed_mapped=no
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+/* malloc might have been renamed as rpl_malloc. */
+#undef malloc
+
+/* Thanks to Mike Haertel and Jim Avera for this test.
+ Here is a matrix of mmap possibilities:
+ mmap private not fixed
+ mmap private fixed at somewhere currently unmapped
+ mmap private fixed at somewhere already mapped
+ mmap shared not fixed
+ mmap shared fixed at somewhere currently unmapped
+ mmap shared fixed at somewhere already mapped
+ For private mappings, we should verify that changes cannot be read()
+ back from the file, nor mmap's back from the file at a different
+ address. (There have been systems where private was not correctly
+ implemented like the infamous i386 svr4.0, and systems where the
+ VM page cache was not coherent with the file system buffer cache
+ like early versions of FreeBSD and possibly contemporary NetBSD.)
+ For shared mappings, we should conversely verify that changes get
+ propagated back to all the places they're supposed to be.
+
+ Grep wants private fixed already mapped.
+ The main things grep needs to know about mmap are:
+ * does it exist and is it safe to write into the mmap'd area
+ * how to use it (BSD variants) */
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H
+char *malloc ();
+#endif
+
+/* This mess was copied from the GNU getpagesize.h. */
+#ifndef HAVE_GETPAGESIZE
+/* Assume that all systems that can run configure have sys/param.h. */
+# ifndef HAVE_SYS_PARAM_H
+# define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+# define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# ifdef EXEC_PAGESIZE
+# define getpagesize() EXEC_PAGESIZE
+# else /* no EXEC_PAGESIZE */
+# ifdef NBPG
+# define getpagesize() NBPG * CLSIZE
+# ifndef CLSIZE
+# define CLSIZE 1
+# endif /* no CLSIZE */
+# else /* no NBPG */
+# ifdef NBPC
+# define getpagesize() NBPC
+# else /* no NBPC */
+# ifdef PAGESIZE
+# define getpagesize() PAGESIZE
+# endif /* PAGESIZE */
+# endif /* no NBPC */
+# endif /* no NBPG */
+# endif /* no EXEC_PAGESIZE */
+# else /* no HAVE_SYS_PARAM_H */
+# define getpagesize() 8192 /* punt totally */
+# endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+int
+main ()
+{
+ char *data, *data2, *data3;
+ int i, pagesize;
+ int fd;
+
+ pagesize = getpagesize ();
+
+ /* First, make a file with some known garbage in it. */
+ data = (char *) malloc (pagesize);
+ if (!data)
+ return 1;
+ for (i = 0; i < pagesize; ++i)
+ *(data + i) = rand ();
+ umask (0);
+ fd = creat ("conftest.mmap", 0600);
+ if (fd < 0)
+ return 1;
+ if (write (fd, data, pagesize) != pagesize)
+ return 1;
+ close (fd);
+
+ /* Next, try to mmap the file at a fixed address which already has
+ something else allocated at it. If we can, also make sure that
+ we see the same garbage. */
+ fd = open ("conftest.mmap", O_RDWR);
+ if (fd < 0)
+ return 1;
+ data2 = (char *) malloc (2 * pagesize);
+ if (!data2)
+ return 1;
+ data2 += (pagesize - ((long int) data2 & (pagesize - 1))) & (pagesize - 1);
+ if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED, fd, 0L))
+ return 1;
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data2 + i))
+ return 1;
+
+ /* Finally, make sure that changes to the mapped area do not
+ percolate back to the file as seen by read(). (This is a bug on
+ some variants of i386 svr4.0.) */
+ for (i = 0; i < pagesize; ++i)
+ *(data2 + i) = *(data2 + i) + 1;
+ data3 = (char *) malloc (pagesize);
+ if (!data3)
+ return 1;
+ if (read (fd, data3, pagesize) != pagesize)
+ return 1;
+ for (i = 0; i < pagesize; ++i)
+ if (*(data + i) != *(data3 + i))
+ return 1;
+ close (fd);
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_func_mmap_fixed_mapped=yes
+else
+ ac_cv_func_mmap_fixed_mapped=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5
+$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; }
+if test $ac_cv_func_mmap_fixed_mapped = yes; then
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+
+fi
+rm -f conftest.mmap
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5
$as_echo_n "checking for library containing dlopen... " >&6; }
if test "${ac_cv_search_dlopen+set}" = set; then :
diff --git a/ld/configure.ac b/ld/configure.ac
index 043c597794f..e926c03dbfc 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -195,6 +195,9 @@ AC_CHECK_FUNCS(glob mkstemp realpath sbrk setlocale waitpid)
AC_CHECK_FUNCS(open lseek close)
AC_HEADER_DIRENT
+dnl AC_CHECK_HEADERS(sys/mman.h)
+AC_FUNC_MMAP
+
AC_SEARCH_LIBS([dlopen], [dl])
AM_CONDITIONAL([ENABLE_PLUGINS], [test x$plugins = xyes])
diff --git a/ld/plugin.c b/ld/plugin.c
index ae0ac8976c4..7ee45a2eccf 100644
--- a/ld/plugin.c
+++ b/ld/plugin.c
@@ -32,6 +32,18 @@
#include "plugin.h"
#include "plugin-api.h"
#include "elf-bfd.h"
+#if HAVE_MMAP
+# include <sys/mman.h>
+# ifndef MAP_FAILED
+# define MAP_FAILED ((void *) -1)
+# endif
+# ifndef PROT_READ
+# define PROT_READ 0
+# endif
+# ifndef MAP_PRIVATE
+# define MAP_PRIVATE 0
+# endif
+#endif
#include <errno.h>
#if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO))
extern int errno;
@@ -76,11 +88,19 @@ typedef struct plugin
bfd_boolean cleanup_done;
} plugin_t;
+typedef struct view_buffer
+{
+ char *addr;
+ size_t filesize;
+ off_t offset;
+} view_buffer_t;
+
/* The internal version of struct ld_plugin_input_file with a BFD
pointer. */
typedef struct plugin_input_file
{
bfd *abfd;
+ view_buffer_t view_buffer;
char *name;
int fd;
off_t offset;
@@ -475,35 +495,63 @@ get_input_file (const void *handle, struct ld_plugin_input_file *file)
static enum ld_plugin_status
get_view (const void *handle, const void **viewp)
{
- const plugin_input_file_t *input = handle;
+ plugin_input_file_t *input = (plugin_input_file_t *) handle;
char *buffer;
- size_t size;
+ size_t size = input->filesize;
ASSERT (called_plugin);
- if (lseek (input->fd, input->offset, SEEK_SET) < 0)
- return LDPS_ERR;
+ /* FIXME: einfo should support %lld. */
+ if ((off_t) size != input->filesize)
+ einfo (_("%P%F: unsupported input file size: %s (%ld bytes)\n"),
+ input->name, (long) input->filesize);
- size = input->filesize;
- buffer = bfd_alloc (input->abfd, size);
- if (buffer == NULL)
- return LDPS_ERR;
- *viewp = buffer;
+ /* Check the cached view buffer. */
+ if (input->view_buffer.addr != NULL
+ && input->view_buffer.filesize == size
+ && input->view_buffer.offset == input->offset)
+ {
+ *viewp = input->view_buffer.addr;
+ return LDPS_OK;
+ }
+
+ input->view_buffer.filesize = size;
+ input->view_buffer.offset = input->offset;
- do
+#if HAVE_MMAP
+ buffer = mmap (NULL, size, PROT_READ, MAP_PRIVATE, input->fd,
+ input->offset);
+ if (buffer == MAP_FAILED)
+#endif
{
- ssize_t got = read (input->fd, buffer, size);
- if (got == 0)
- break;
- else if (got > 0)
+ char *p;
+
+ if (lseek (input->fd, input->offset, SEEK_SET) < 0)
+ return LDPS_ERR;
+
+ buffer = bfd_alloc (input->abfd, size);
+ if (buffer == NULL)
+ return LDPS_ERR;
+
+ p = buffer;
+ do
{
- buffer += got;
- size -= got;
+ ssize_t got = read (input->fd, p, size);
+ if (got == 0)
+ break;
+ else if (got > 0)
+ {
+ p += got;
+ size -= got;
+ }
+ else if (errno != EINTR)
+ return LDPS_ERR;
}
- else if (errno != EINTR)
- return LDPS_ERR;
+ while (size > 0);
}
- while (size > 0);
+
+ input->view_buffer.addr = buffer;
+ *viewp = buffer;
return LDPS_OK;
}
@@ -951,6 +999,9 @@ plugin_maybe_claim (struct ld_plugin_input_file *file,
bfd_get_error ());
input->abfd = abfd;
+ input->view_buffer.addr = NULL;
+ input->view_buffer.filesize = 0;
+ input->view_buffer.offset = 0;
input->fd = file->fd;
input->offset = file->offset;
input->filesize = file->filesize;