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:
H.J. Lu 2015-02-06 09:05:35 -08:00
parent d6c146e9ea
commit 2aec968d4d
5 changed files with 278 additions and 22 deletions

View File

@ -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.

View File

@ -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
View File

@ -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 :

View File

@ -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])

View File

@ -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;