Speed-up elf_begin when not using mmap.
authorUlrich Drepper <drepper@redhat.com>
Sun, 28 Aug 2005 02:46:32 +0000 (02:46 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 28 Aug 2005 02:46:32 +0000 (02:46 +0000)
NEWS
configure.ac
libelf/ChangeLog
libelf/elf_begin.c

diff --git a/NEWS b/NEWS
index a15e1f1..bd70d66 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.115:
+
+libelf: speed-ups of non-mmap reading.
+
 Version 0.114:
 
 libelf: new function elf_getaroff
index f8d4ef3..cdade45 100644 (file)
@@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License
 dnl along with this program; if not, write to the Free Software Foundation,
 dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 dnl
-AC_INIT([Red Hat elfutils],[0.114],[http://bugzilla.redhat.com/bugzilla/],
+AC_INIT([Red Hat elfutils],[0.115],[http://bugzilla.redhat.com/bugzilla/],
        [elfutils])
 
 AC_CONFIG_AUX_DIR([config])
index 5c68569..6c8b5b1 100644 (file)
@@ -1,3 +1,10 @@
+2005-08-27  Ulrich Drepper  <drepper@redhat.com>
+
+       * elf_begin.c (file_read_elf): Avoid reading ELF header from file
+       again.  Instead accept additional parameter which points to it if we
+       don't use mmap.
+       (get_shnum): Use passed in e_ident value as source of ELF header.
+
 2005-08-15  Ulrich Drepper  <drepper@redhat.com>
 
        * elf_begin.c (__libelf_next_arhdr): Use TEMP_FAILURE_RETRY.
index c4b3359..5d6f1b2 100644 (file)
@@ -77,41 +77,25 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
   bool is32 = e_ident[EI_CLASS] == ELFCLASS32;
 
   /* Make the ELF header available.  */
-  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA
-      && (ALLOW_UNALIGNED
-         || (((size_t) ((char *) map_address + offset))
-             & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr))
-                - 1)) == 0))
-    ehdr.p = (char *) map_address + offset;
+  if (e_ident[EI_DATA] == MY_ELFDATA)
+    ehdr.p = e_ident;
   else
     {
-      /* We have to read the data from the file.  */
-      size_t len = is32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr);
+      /* We already read the ELF header.  We have to copy the header
+        since we possibly modify the data here and the caller
+        expects the memory it passes in to be preserved.  */
+      ehdr.p = memcpy (&ehdr_mem, e_ident,
+                      is32 ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr));
 
-      if (likely (map_address != NULL))
-       ehdr.p = memcpy (&ehdr_mem, (char *) map_address + offset, len);
-      else
+      if (is32)
        {
-         /* Fill it.  */
-         if ((size_t) TEMP_FAILURE_RETRY (pread (fildes, &ehdr_mem, len,
-                                                 offset)) != len)
-           /* Failed reading.  */
-           return (size_t) -1l;
-         ehdr.p = &ehdr_mem;
+         CONVERT (ehdr.e32->e_shnum);
+         CONVERT (ehdr.e32->e_shoff);
        }
-
-      if (e_ident[EI_DATA] != MY_ELFDATA)
+      else
        {
-         if (is32)
-           {
-             CONVERT (ehdr.e32->e_shnum);
-             CONVERT (ehdr.e32->e_shoff);
-           }
-         else
-           {
-             CONVERT (ehdr.e64->e_shnum);
-             CONVERT (ehdr.e64->e_shoff);
-           }
+         CONVERT (ehdr.e64->e_shnum);
+         CONVERT (ehdr.e64->e_shoff);
        }
     }
 
@@ -215,31 +199,9 @@ get_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,
 
 /* Create descriptor for ELF file in memory.  */
 static Elf *
-file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
-              Elf_Cmd cmd, Elf *parent)
+file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
+              off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent)
 {
-  /* We only read the ELF header now.  */
-  unsigned char *e_ident;
-  unsigned char e_ident_mem[EI_NIDENT];
-  size_t scncnt;
-  Elf *elf;
-
-  if (map_address != NULL)
-    /* It's right at the beginning of the file.  No word access
-       required, just bytes.  */
-    e_ident = (unsigned char *) map_address + offset;
-  else
-    {
-      e_ident = e_ident_mem;
-
-      if (TEMP_FAILURE_RETRY (pread (fildes, e_ident, EI_NIDENT, offset))
-         != EI_NIDENT)
-       {
-         __libelf_seterrno (ELF_E_READ_ERROR);
-         return NULL;
-       }
-    }
-
   /* Verify the binary is of the class we can handle.  */
   if ((e_ident[EI_CLASS] != ELFCLASS32
        && e_ident[EI_CLASS] != ELFCLASS64)
@@ -253,14 +215,14 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
     }
 
   /* Determine the number of sections.  */
-  scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);
+  size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);
   if (scncnt == (size_t) -1l)
     /* Could not determine the number of sections.  */
     return NULL;
 
   /* We can now allocate the memory.  */
-  elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
-                     ELF_K_ELF, scncnt * sizeof (Elf_Scn));
+  Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,
+                          ELF_K_ELF, scncnt * sizeof (Elf_Scn));
   if (elf == NULL)
     /* Not enough memory.  */
     return NULL;
@@ -319,16 +281,8 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
            memcpy (&elf->state.elf32.ehdr_mem,
                    (char *) map_address + offset, sizeof (Elf32_Ehdr));
          else
-           /* Read the data.  */
-           if (TEMP_FAILURE_RETRY (pread (elf->fildes,
-                                          &elf->state.elf32.ehdr_mem,
-                                          sizeof (Elf32_Ehdr), offset))
-               != sizeof (Elf32_Ehdr))
-             {
-               /* We must be able to read the ELF header.  */
-               __libelf_seterrno (ELF_E_INVALID_FILE);
-               return NULL;
-             }
+           /* Copy the data.  */
+           memcpy (&elf->state.elf32.ehdr_mem, e_ident, sizeof (Elf32_Ehdr));
 
          if (e_ident[EI_DATA] != MY_ELFDATA)
            {
@@ -411,16 +365,8 @@ file_read_elf (int fildes, void *map_address, off_t offset, size_t maxsize,
            memcpy (&elf->state.elf64.ehdr_mem,
                    (char *) map_address + offset, sizeof (Elf64_Ehdr));
          else
-           /* Read the data.  */
-           if (TEMP_FAILURE_RETRY (pread (elf->fildes,
-                                          &elf->state.elf64.ehdr_mem,
-                                          sizeof (Elf64_Ehdr), offset))
-               != sizeof (Elf64_Ehdr))
-           {
-             /* We must be able to read the ELF header.  */
-             __libelf_seterrno (ELF_E_INVALID_FILE);
-             return NULL;
-           }
+           /* Copy the data.  */
+           memcpy (&elf->state.elf64.ehdr_mem, e_ident, sizeof (Elf64_Ehdr));
 
          if (e_ident[EI_DATA] != MY_ELFDATA)
            {
@@ -469,15 +415,16 @@ __libelf_read_mmaped_file (int fildes, void *map_address,  off_t offset,
      files and archives.  To find out what we have we must look at the
      header.  The header for an ELF file is EI_NIDENT bytes in size,
      the header for an archive file SARMAG bytes long.  */
-  Elf_Kind kind;
+  unsigned char *e_ident = (unsigned char *) map_address + offset;
 
   /* See what kind of object we have here.  */
-  kind = determine_kind (map_address + offset, maxsize);
+  Elf_Kind kind = determine_kind (e_ident, maxsize);
 
   switch (kind)
     {
     case ELF_K_ELF:
-      return file_read_elf (fildes, map_address, offset, maxsize, cmd, parent);
+      return file_read_elf (fildes, map_address, e_ident, offset, maxsize,
+                           cmd, parent);
 
     case ELF_K_AR:
       return file_read_ar (fildes, map_address, offset, maxsize, cmd, parent);
@@ -499,25 +446,33 @@ read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd,
 {
   /* We have to find out what kind of file this is.  We handle ELF
      files and archives.  To find out what we have we must read the
-     header.  The header for an ELF file is EI_NIDENT bytes in size,
-     the header for an archive file SARMAG bytes long.  Read the
-     maximum of these numbers.
+     header.  The identification header for an ELF file is EI_NIDENT
+     bytes in size, but we read the whole ELF header since we will
+     need it anyway later.  For archives the header in SARMAG bytes
+     long.  Read the maximum of these numbers.
 
-     XXX We have to change this for the extended `ar' format some day.  */
-  unsigned char header[MAX (EI_NIDENT, SARMAG)];
-  ssize_t nread;
-  Elf_Kind kind;
+     XXX We have to change this for the extended `ar' format some day.
+
+     Use a union to ensure alignment.  We might later access the
+     memory as a ElfXX_Ehdr.  */
+  union
+  {
+    Elf64_Ehdr ehdr;
+    unsigned char header[MAX (sizeof (Elf64_Ehdr), SARMAG)];
+  } mem;
 
   /* Read the head of the file.  */
-  nread = pread (fildes, header, MIN (MAX (EI_NIDENT, SARMAG), maxsize),
-                offset);
+  ssize_t nread = pread (fildes, mem.header, MIN (MAX (sizeof (Elf64_Ehdr),
+                                                      SARMAG),
+                                                 maxsize),
+                        offset);
   if (nread == -1)
     /* We cannot even read the head of the file.  Maybe FILDES is associated
        with an unseekable device.  This is nothing we can handle.  */
     return NULL;
 
   /* See what kind of object we have here.  */
-  kind = determine_kind (header, nread);
+  Elf_Kind kind = determine_kind (mem.header, nread);
 
   switch (kind)
     {
@@ -526,9 +481,10 @@ read_unmmaped_file (int fildes, off_t offset, size_t maxsize, Elf_Cmd cmd,
 
     case ELF_K_ELF:
       /* Make sure at least the ELF header is contained in the file.  */
-      if (maxsize >= (header[EI_CLASS] == ELFCLASS32
-                     ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)))
-       return file_read_elf (fildes, NULL, offset, maxsize, cmd, parent);
+      if ((size_t) nread >= (mem.header[EI_CLASS] == ELFCLASS32
+                            ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr)))
+       return file_read_elf (fildes, NULL, mem.header, offset, maxsize, cmd,
+                             parent);
       /* FALLTHROUGH */
 
     default:
@@ -596,10 +552,11 @@ read_file (int fildes, off_t offset, size_t maxsize,
   /* If we have the file in memory optimize the access.  */
   if (map_address != NULL)
     {
-      struct Elf *result;
+      assert (map_address != MAP_FAILED);
 
-      result = __libelf_read_mmaped_file (fildes, map_address, offset, maxsize,
-                                         cmd, parent);
+      struct Elf *result = __libelf_read_mmaped_file (fildes, map_address,
+                                                     offset, maxsize, cmd,
+                                                     parent);
 
       /* If something went wrong during the initialization unmap the
         memory if we mmaped here.  */