guile-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Guile-commits] GNU Guile branch, wip-rtl, updated. v2.0.5-916-gc34484d


From: Andy Wingo
Subject: [Guile-commits] GNU Guile branch, wip-rtl, updated. v2.0.5-916-gc34484d
Date: Sun, 28 Apr 2013 12:42:07 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU Guile".

http://git.savannah.gnu.org/cgit/guile.git/commit/?id=c34484dde68b5977e8c335e14c54394533b19e14

The branch, wip-rtl has been updated
       via  c34484dde68b5977e8c335e14c54394533b19e14 (commit)
       via  8b8af9ea7af711206c65caf0e009f2edb5efb563 (commit)
      from  4a0b6a0f117671e7f6e07fafb68d4cedfabbbbea (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c34484dde68b5977e8c335e14c54394533b19e14
Author: Andy Wingo <address@hidden>
Date:   Sun Apr 28 14:42:01 2013 +0200

    add (mapped-elf-images) procedure to (system vm objcode) module
    
    * libguile/objcodes.c (register_elf, scm_mapped_elf_images): New
      interfaces that keep a list of all ELF mappings.  Exported to (but not
      from) the (system vm objcode) module.

commit 8b8af9ea7af711206c65caf0e009f2edb5efb563
Author: Andy Wingo <address@hidden>
Date:   Sun Apr 28 14:23:20 2013 +0200

    refactor and simplify ELF loader in objcodes.c
    
    * libguile/objcodes.c (sniff_elf_alignment, alloc_aligned)
      (copy_and_align_elf_data): New helpers for portably re-aligning ELF
      data from read(2) or from a bytevector.
      (load_thunk_from_memory): Simplify!  Now there is only one procedure
      that loads ELF, and it does less: it simply receives the whole image
      in one array, hopefully from mmap.
    
      (scm_load_thunk_from_file): Use new map_file_contents helper, and go
      through load_thunk_from_memory.
      (scm_load_thunk_from_memory): Pass load_thunk_from_memory a piece of
      memory that it owns, and that is appropriately aligned.

-----------------------------------------------------------------------

Summary of changes:
 libguile/objcodes.c |  468 +++++++++++++++++++++++++--------------------------
 1 files changed, 227 insertions(+), 241 deletions(-)

diff --git a/libguile/objcodes.c b/libguile/objcodes.c
index 0639028..4551887 100644
--- a/libguile/objcodes.c
+++ b/libguile/objcodes.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, 
Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -88,6 +88,8 @@
 #define ELFDATA ELFDATA2LSB
 #endif
 
+static void register_elf (char *data, size_t len);
+
 enum bytecode_kind
   {
     BYTECODE_KIND_NONE,
@@ -160,48 +162,104 @@ check_elf_header (const Elf_Ehdr *header)
   return NULL;
 }
 
-static int
-segment_flags_to_prot (Elf_Word flags)
+#define IS_ALIGNED(offset, alignment) \
+  (!((offset) & ((alignment) - 1)))
+#define ALIGN(offset, alignment) \
+  ((offset + (alignment - 1)) & ~(alignment - 1))
+
+static unsigned
+sniff_elf_alignment (const char *data, size_t len)
 {
-  int prot = 0;
-          
-  if (flags & PF_X)
-    prot |= PROT_EXEC;
-  if (flags & PF_W)
-    prot |= PROT_WRITE;
-  if (flags & PF_R)
-    prot |= PROT_READ;
+  Elf_Ehdr *header;
+  int i;
+  unsigned alignment = 8;
+
+  if (len < sizeof(Elf_Ehdr))
+    return alignment;
+  header = (Elf_Ehdr *) data;
+  if (header->e_phoff + header->e_phnum * header->e_phentsize >= len)
+    return alignment;
+  for (i = 0; i < header->e_phnum; i++)
+    {
+      Elf_Phdr *phdr;
+      const char *phdr_addr = data + header->e_phoff + i * header->e_phentsize;
 
-  return prot;
+      if (!IS_ALIGNED ((scm_t_uintptr) phdr_addr, alignof_type (Elf_Phdr)))
+        return alignment;
+      phdr = (Elf_Phdr *) phdr_addr;
+
+      if (phdr->p_align & (phdr->p_align - 1))
+        return alignment;
+
+      if (phdr->p_align > alignment)
+        alignment = phdr->p_align;
+    }
+
+  return alignment;
 }
 
-static int
-map_segments (int fd, char **base,
-              const Elf_Phdr *from, const Elf_Phdr *to)
+/* This function leaks the memory that it allocates.  */
+static char*
+alloc_aligned (size_t len, unsigned alignment)
 {
-  int prot = segment_flags_to_prot (from->p_flags);
   char *ret;
 
-  ret = mmap (*base + from->p_vaddr,
-              to->p_offset + to->p_filesz - from->p_offset,
-              prot, MAP_PRIVATE, fd, from->p_offset);
+  if (alignment == 8)
+    {
+      /* FIXME: Assert that we actually have an 8-byte-aligned malloc.  */
+      ret = malloc (len);
+    }
+#if defined(HAVE_SYS_MMAN_H) && defined(MMAP_ANONYMOUS)
+  else if (alignment == SCM_PAGE_SIZE)
+    {
+      ret = mmap (NULL, len, PROT_READ | PROT_WRITE, -1, 0);
+      if (ret == MAP_FAILED)
+        SCM_SYSERROR;
+    }
+#endif
+  else
+    {
+      if (len + alignment < len)
+        abort ();
+
+      ret = malloc (len + alignment - 1);
+      if (!ret)
+        abort ();
+      ret = (char *) ALIGN ((scm_t_uintptr) ret, alignment);
+    }
 
-  if (ret == (char *) -1)
-    return 1;
+  return ret;
+}
 
-  if (!*base)
-    *base = ret;
+static char*
+copy_and_align_elf_data (const char *data, size_t len)
+{
+  unsigned alignment;
+  char *copy;
+
+  alignment = sniff_elf_alignment (data, len);
+  copy = alloc_aligned (len, alignment);
+  memcpy(copy, data, len);
 
-  return 0;
+  return copy;
 }
 
+#ifdef HAVE_SYS_MMAN_H
 static int
-mprotect_segments (char *base, const Elf_Phdr *from, const Elf_Phdr *to)
+segment_flags_to_prot (Elf_Word flags)
 {
-  return mprotect (base + from->p_vaddr,
-                   to->p_vaddr + to->p_memsz - from->p_vaddr,
-                   segment_flags_to_prot (from->p_flags));
+  int prot = 0;
+
+  if (flags & PF_X)
+    prot |= PROT_EXEC;
+  if (flags & PF_W)
+    prot |= PROT_WRITE;
+  if (flags & PF_R)
+    prot |= PROT_READ;
+
+  return prot;
 }
+#endif
 
 static char*
 process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
@@ -299,152 +357,38 @@ process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
 
 #define ABORT(msg) do { err_msg = msg; goto cleanup; } while (0)
 
-#ifdef HAVE_SYS_MMAN_H
 static SCM
-load_thunk_from_fd_using_mmap (int fd)
-#define FUNC_NAME "load-thunk-from-disk"
+load_thunk_from_memory (char *data, size_t len, int is_read_only)
+#define FUNC_NAME "load-thunk-from-memory"
 {
-  Elf_Ehdr header;
+  Elf_Ehdr *header;
   Elf_Phdr *ph;
   const char *err_msg = 0;
-  char *base = 0;
-  size_t n;
+  size_t n, alignment = 8;
   int i;
-  int start_segment = -1;
-  int prev_segment = -1;
   int dynamic_segment = -1;
   SCM init = SCM_BOOL_F, entry = SCM_BOOL_F;
 
-  if (full_read (fd, &header, sizeof header) != sizeof header)
+  if (len < sizeof *header)
     ABORT ("object file too small");
 
-  if ((err_msg = check_elf_header (&header)))
-    goto cleanup;
-
-  if (lseek (fd, header.e_phoff, SEEK_SET) == (off_t) -1)
-    goto cleanup;
+  header = (Elf_Ehdr*) data;
   
-  n = header.e_phnum;
-  ph = scm_gc_malloc_pointerless (n * sizeof (Elf_Phdr), "segment headers");
-
-  if (full_read (fd, ph, n * sizeof (Elf_Phdr)) != n * sizeof (Elf_Phdr))
-    ABORT ("failed to read program headers");
-      
-  for (i = 0; i < n; i++)
-    {
-      if (!ph[i].p_memsz)
-        continue;
-
-      if (ph[i].p_filesz != ph[i].p_memsz)
-        ABORT ("expected p_filesz == p_memsz");
-      
-      if (!ph[i].p_flags)
-        ABORT ("expected nonzero segment flags");
-
-      if (ph[i].p_type == PT_DYNAMIC)
-        {
-          if (dynamic_segment >= 0)
-            ABORT ("expected only one PT_DYNAMIC segment");
-          dynamic_segment = i;
-        }
-
-      if (start_segment < 0)
-        {
-          if (!base && ph[i].p_vaddr)
-            ABORT ("first loadable vaddr is not 0");
-            
-          start_segment = prev_segment = i;
-          continue;
-        }
-
-      if (ph[i].p_flags == ph[start_segment].p_flags)
-        {
-          if (ph[i].p_vaddr - ph[prev_segment].p_vaddr 
-              != ph[i].p_offset - ph[prev_segment].p_offset)
-            ABORT ("coalesced segments not contiguous");
-
-          prev_segment = i;
-          continue;
-        }
-
-      /* Otherwise we have a new kind of segment.  Map previous
-         segments.  */
-      if (map_segments (fd, &base, &ph[start_segment], &ph[prev_segment]))
-        goto cleanup;
-
-      /* Open a new set of segments.  */
-      start_segment = prev_segment = i;
-    }
-
-  /* Map last segments.  */
-  if (start_segment < 0)
-    ABORT ("no loadable segments");
-
-  if (map_segments (fd, &base, &ph[start_segment], &ph[prev_segment]))
-    goto cleanup;
-
-  if (dynamic_segment < 0)
-    ABORT ("no PT_DYNAMIC segment");
-
-  if ((err_msg = process_dynamic_segment (base, &ph[dynamic_segment],
-                                          &init, &entry)))
+  if ((err_msg = check_elf_header (header)))
     goto cleanup;
 
-  if (scm_is_true (init))
-    scm_call_0 (init);
-
-  /* Finally!  Return the thunk.  */
-  return entry;
-
-  /* FIXME: munmap on error? */
- cleanup:
-  {
-    int errno_save = errno;
-    (void) close (fd);
-    errno = errno_save;
-    if (errno)
-      SCM_SYSERROR;
-    scm_misc_error (FUNC_NAME, err_msg ? err_msg : "error loading ELF file",
-                    SCM_EOL);
-  }
-}
-#undef FUNC_NAME
-#endif /* HAVE_SYS_MMAN_H */
-
-static SCM
-load_thunk_from_memory (char *data, size_t len)
-#define FUNC_NAME "load-thunk-from-memory"
-{
-  Elf_Ehdr header;
-  Elf_Phdr *ph;
-  const char *err_msg = 0;
-  char *base = 0;
-  size_t n, memsz = 0, alignment = 8;
-  int i;
-  int first_loadable = -1;
-  int start_segment = -1;
-  int prev_segment = -1;
-  int dynamic_segment = -1;
-  SCM init = SCM_BOOL_F, entry = SCM_BOOL_F;
+  if (header->e_phnum == 0)
+    ABORT ("no loadable segments");
+  n = header->e_phnum;
 
-  if (len < sizeof header)
+  if (len < header->e_phoff + n * sizeof (Elf_Phdr))
     ABORT ("object file too small");
 
-  memcpy (&header, data, sizeof header);
-
-  if ((err_msg = check_elf_header (&header)))
-    goto cleanup;
-
-  n = header.e_phnum;
-  if (len < header.e_phoff + n * sizeof (Elf_Phdr))
-    goto cleanup;
-  ph = (Elf_Phdr*) (data + header.e_phoff);
+  ph = (Elf_Phdr*) (data + header->e_phoff);
 
+  /* Check that the segment table is sane.  */
   for (i = 0; i < n; i++)
     {
-      if (!ph[i].p_memsz)
-        continue;
-
       if (ph[i].p_filesz != ph[i].p_memsz)
         ABORT ("expected p_filesz == p_memsz");
 
@@ -465,90 +409,57 @@ load_thunk_from_memory (char *data, size_t len)
           dynamic_segment = i;
         }
 
-      if (first_loadable < 0)
+      if (i == 0)
         {
-          if (ph[i].p_vaddr)
+          if (ph[i].p_vaddr != 0)
             ABORT ("first loadable vaddr is not 0");
-
-          first_loadable = i;
         }
+      else
+        {
+          if (ph[i].p_vaddr < ph[i-1].p_vaddr + ph[i-1].p_memsz)
+            ABORT ("overlapping segments");
 
-      if (ph[i].p_vaddr < memsz)
-        ABORT ("overlapping segments");
-
-      if (ph[i].p_offset + ph[i].p_filesz > len)
-        ABORT ("segment beyond end of byte array");
-
-      memsz = ph[i].p_vaddr + ph[i].p_memsz;
+          if (ph[i].p_offset + ph[i].p_filesz > len)
+            ABORT ("segment beyond end of byte array");
+        }
     }
 
-  if (first_loadable < 0)
-    ABORT ("no loadable segments");
-
   if (dynamic_segment < 0)
     ABORT ("no PT_DYNAMIC segment");
 
-  /* Now copy segments.  */
+  if (!IS_ALIGNED ((scm_t_uintptr) data, alignment))
+    ABORT ("incorrectly aligned base");
 
-  /* We leak this memory, as we leak the memory mappings in
-     load_thunk_from_fd_using_mmap.
-
-     If the file is has an alignment of 8, use the standard malloc.
-     (FIXME to ensure alignment on non-GNU malloc.)  Otherwise use
-     posix_memalign.  We only use mprotect if the aligment is 4096.  */
-  if (alignment == 8)
+  /* Allow writes to writable pages.  */
+  if (is_read_only)
     {
-      base = malloc (memsz);
-      if (!base)
-        goto cleanup;
-    }
-  else
-    if ((errno = posix_memalign ((void **) &base, alignment, memsz)))
-      goto cleanup;
-
-  memset (base, 0, memsz);
-
-  for (i = 0; i < n; i++)
-    {
-      if (!ph[i].p_memsz)
-        continue;
-
-      memcpy (base + ph[i].p_vaddr,
-              data + ph[i].p_offset,
-              ph[i].p_memsz);
-
-      if (start_segment < 0)
-        {
-          start_segment = prev_segment = i;
-          continue;
-        }
-
-      if (ph[i].p_flags == ph[start_segment].p_flags)
+#ifdef HAVE_SYS_MMAN_H
+      for (i = 0; i < n; i++)
         {
-          prev_segment = i;
-          continue;
+          if (ph[i].p_flags == PF_R)
+            continue;
+          if (ph[i].p_align != 4096)
+            continue;
+
+          if (mprotect (data + ph[i].p_vaddr,
+                        ph[i].p_memsz,
+                        segment_flags_to_prot (ph[i].p_flags)))
+            goto cleanup;
         }
-
-      if (alignment == 4096)
-        if (mprotect_segments (base, &ph[start_segment], &ph[prev_segment]))
-          goto cleanup;
-
-      /* Open a new set of segments.  */
-      start_segment = prev_segment = i;
+#else
+      ABORT ("expected writable pages");
+#endif
     }
 
-  /* Mprotect the last segments.  */
-  if (alignment == 4096)
-    if (mprotect_segments (base, &ph[start_segment], &ph[prev_segment]))
-      goto cleanup;
-
-  if ((err_msg = process_dynamic_segment (base, &ph[dynamic_segment],
+  if ((err_msg = process_dynamic_segment (data, &ph[dynamic_segment],
                                           &init, &entry)))
     goto cleanup;
 
   if (scm_is_true (init))
     scm_call_0 (init);
 
+  register_elf (data, len);
+
   /* Finally!  Return the thunk.  */
   return entry;
 
@@ -562,22 +473,40 @@ load_thunk_from_memory (char *data, size_t len)
 }
 #undef FUNC_NAME
 
-#ifndef HAVE_SYS_MMAN_H
-static SCM
-load_thunk_from_fd_using_read (int fd)
-#define FUNC_NAME "load-thunk-from-disk"
+#define SCM_PAGE_SIZE 4096
+
+static char*
+map_file_contents (int fd, size_t len, int *is_read_only)
+#define FUNC_NAME "load-thunk-from-file"
 {
   char *data;
-  size_t len;
-  struct stat st;
-  int ret;
 
-  ret = fstat (fd, &st);
-  if (ret < 0)
+#ifdef HAVE_SYS_MMAN_H
+  data = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
+  if (data == MAP_FAILED)
     SCM_SYSERROR;
-  len = st.st_size;
-  data = scm_gc_malloc_pointerless (len, "objcode");
-  if (full_read (fd, data, len) != len)
+  *is_read_only = 1;
+#else
+  if (lseek (fd, 0, SEEK_START) < 0)
+    {
+      int errno_save = errno;
+      (void) close (fd);
+      errno = errno_save;
+      SCM_SYSERROR;
+    }
+
+  /* Given that we are using the read fallback, optimistically assume
+     that the .go files were made with 8-byte alignment.
+     alignment.  */
+  data = malloc (end);
+  if (!data)
+    {
+      (void) close (fd);
+      scm_misc_error (FUNC_NAME, "failed to allocate ~A bytes",
+                      scm_list_1 (scm_from_size_t (end)));
+    }
+
+  if (full_read (fd, data, end) != end)
     {
       int errno_save = errno;
       (void) close (fd);
@@ -587,11 +516,25 @@ load_thunk_from_fd_using_read (int fd)
       scm_misc_error (FUNC_NAME, "short read while loading objcode",
                       SCM_EOL);
     }
-  (void) close (fd);
-  return load_thunk_from_memory (data, len);
+
+  /* If our optimism failed, fall back.  */
+  {
+    unsigned alignment = sniff_elf_alignment (data, end);
+
+    if (alignment != 8)
+      {
+        char *copy = copy_and_align_elf_data (data, end, alignment);
+        free (data);
+        data = copy;
+      }
+  }
+
+  *is_read_only = 0;
+#endif
+
+  return data;
 }
 #undef FUNC_NAME
-#endif /* ! HAVE_SYS_MMAN_H */
 
 SCM_DEFINE (scm_load_thunk_from_file, "load-thunk-from-file", 1, 0, 0,
            (SCM filename),
@@ -599,7 +542,9 @@ SCM_DEFINE (scm_load_thunk_from_file, 
"load-thunk-from-file", 1, 0, 0,
 #define FUNC_NAME s_scm_load_thunk_from_file
 {
   char *c_filename;
-  int fd;
+  int fd, is_read_only;
+  off_t end;
+  char *data;
 
   SCM_VALIDATE_STRING (1, filename);
 
@@ -608,11 +553,15 @@ SCM_DEFINE (scm_load_thunk_from_file, 
"load-thunk-from-file", 1, 0, 0,
   free (c_filename);
   if (fd < 0) SCM_SYSERROR;
 
-#ifdef HAVE_SYS_MMAN_H
-  return load_thunk_from_fd_using_mmap (fd);
-#else
-  return load_thunk_from_fd_using_read (fd);
-#endif
+  end = lseek (fd, 0, SEEK_END);
+  if (end < 0)
+    SCM_SYSERROR;
+
+  data = map_file_contents (fd, end, &is_read_only);
+
+  (void) close (fd);
+
+  return load_thunk_from_memory (data, end, is_read_only);
 }
 #undef FUNC_NAME
 
@@ -621,10 +570,20 @@ SCM_DEFINE (scm_load_thunk_from_memory, 
"load-thunk-from-memory", 1, 0, 0,
            "")
 #define FUNC_NAME s_scm_load_thunk_from_memory
 {
+  char *data;
+  size_t len;
+
   SCM_VALIDATE_BYTEVECTOR (1, bv);
 
-  return load_thunk_from_memory ((char *) SCM_BYTEVECTOR_CONTENTS (bv),
-                                 SCM_BYTEVECTOR_LENGTH (bv));
+  data = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
+  len = SCM_BYTEVECTOR_LENGTH (bv);
+
+  /* Copy data in order to align it, to trace its GC roots and
+     writable sections, and to keep it in memory.  */
+
+  data = copy_and_align_elf_data (data, len);
+
+  return load_thunk_from_memory (data, len, 0);
 }
 #undef FUNC_NAME
 
@@ -679,6 +638,30 @@ scm_c_make_objcode_slice (SCM parent, const scm_t_uint8 
*ptr)
 }
 #undef FUNC_NAME
 
+static SCM mapped_elf_images = SCM_EOL;
+
+static void
+register_elf (char *data, size_t len)
+{
+  SCM bv = scm_c_take_gc_bytevector ((signed char *) data, len, SCM_BOOL_F);
+
+  scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
+  mapped_elf_images = scm_cons (bv, mapped_elf_images);
+  scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
+}
+
+static SCM
+scm_mapped_elf_images (void)
+{
+  SCM ret;
+
+  scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
+  ret = mapped_elf_images;
+  scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
+
+  return ret;
+}
+
 
 /*
  * Scheme interface
@@ -817,6 +800,9 @@ scm_init_objcodes (void)
 #include "libguile/objcodes.x"
 #endif
 
+  scm_c_define_gsubr ("mapped-elf-images", 0, 0, 0,
+                      (scm_t_subr) scm_mapped_elf_images);
+
   scm_c_define ("word-size", scm_from_size_t (sizeof(SCM)));
   scm_c_define ("byte-order", scm_from_uint16 (SCM_BYTE_ORDER));
 }


hooks/post-receive
-- 
GNU Guile



reply via email to

[Prev in Thread] Current Thread [Next in Thread]