Use mmap and cache the view buffer for get_view
This patch uses mmap if it is available and works. It also caches the view buffer for get_view. * 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.
This commit is contained in:
parent
d6c146e9ea
commit
2aec968d4d
5 changed files with 278 additions and 22 deletions
14
ld/ChangeLog
14
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.
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
182
ld/configure
vendored
182
ld/configure
vendored
|
@ -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 :
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
95
ld/plugin.c
95
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;
|
||||
|
||||
do
|
||||
/* Check the cached view buffer. */
|
||||
if (input->view_buffer.addr != NULL
|
||||
&& input->view_buffer.filesize == size
|
||||
&& input->view_buffer.offset == input->offset)
|
||||
{
|
||||
ssize_t got = read (input->fd, buffer, size);
|
||||
if (got == 0)
|
||||
break;
|
||||
else if (got > 0)
|
||||
{
|
||||
buffer += got;
|
||||
size -= got;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
return LDPS_ERR;
|
||||
*viewp = input->view_buffer.addr;
|
||||
return LDPS_OK;
|
||||
}
|
||||
while (size > 0);
|
||||
|
||||
input->view_buffer.filesize = size;
|
||||
input->view_buffer.offset = input->offset;
|
||||
|
||||
#if HAVE_MMAP
|
||||
buffer = mmap (NULL, size, PROT_READ, MAP_PRIVATE, input->fd,
|
||||
input->offset);
|
||||
if (buffer == MAP_FAILED)
|
||||
#endif
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue