CMUCL commit: src (lisp/mach-o.c tools/linker-x86.sh)

Raymond Toy rtoy at common-lisp.net
Sun Aug 1 17:23:28 CEST 2010


    Date: Sunday, August 1, 2010 @ 11:23:28
  Author: rtoy
    Path: /project/cmucl/cvsroot/src

Modified: lisp/mach-o.c tools/linker-x86.sh

No functional changes.  Just update and clarify comments.


---------------------+
 lisp/mach-o.c       |   94 ++++++++++++++++++++++++++++++++++++++++++++++----
 tools/linker-x86.sh |   34 +++++++++++++++---
 2 files changed, 117 insertions(+), 11 deletions(-)


Index: src/lisp/mach-o.c
diff -u src/lisp/mach-o.c:1.4 src/lisp/mach-o.c:1.5
--- src/lisp/mach-o.c:1.4	Fri Jul 30 22:45:45 2010
+++ src/lisp/mach-o.c	Sun Aug  1 11:23:28 2010
@@ -1,3 +1,22 @@
+/*
+ * $Header: /project/cmucl/cvsroot/src/lisp/mach-o.c,v 1.5 2010-08-01 15:23:28 rtoy Exp $
+ *
+ * This code was written by Raymond Toy as part of CMU Common Lisp and
+ * has been placed in the public domain.
+ *
+ * Mach-O support for generating executable images on Mac OS X (aka
+ * Darwin).  This only knows enough of the Mach-O format to be able to
+ * write out very simple object files for the Lisp spaces and to read
+ * just enough of a Mach-O executable to find the segments containing
+ * the Lisp spaces.
+ *
+ * For details of the file format see " Mac OS X ABI Mach-O File
+ * Format Reference",
+ * http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+ *
+ * 
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -77,6 +96,10 @@
     }
 }
 
+/*
+ * Create a file for the specified Lisp space in the specified
+ * directory.
+ */
 static int
 create_mach_o_file (const char *dir, int id)
 {
@@ -96,6 +119,10 @@
     return out;
 }
 
+/*
+ * Write the Mach-O header.  We only handle what we need for our
+ * purposes.
+ */
 static int
 write_mach_o_header(int fd)
 {
@@ -103,8 +130,14 @@
 
     /* Ident array. */
     eh.magic = MH_MAGIC;
-    /* Support any kind x86.  (Should we be more specific?) */
+    /* Currently only support x86's */
     eh.cputype = CPU_TYPE_I386;
+    /*
+     * Support any kind x86.  Should we be more specific?  We need at
+     * least a pentium to run x87.  For SSE2 we need at least a
+     * Pentium 4 chip.  So if the core is SSE2, should we set this to
+     * Pentium 4?
+     */
     eh.cpusubtype = CPU_SUBTYPE_I386_ALL;
 
     eh.filetype = MH_OBJECT;
@@ -118,6 +151,12 @@
     return ewrite(fd, &eh, sizeof(MachO_hdr), __func__);
 }
 
+/*
+ * Write one segment (load) command to the object file in fd.  The
+ * name of the segment is in name.  We also need to specify the
+ * starting VM address (start) and the VM size (length) of the section
+ * of memory that we want this to map to.
+ */
 static int
 write_load_command(int fd, char* name, int length, os_vm_address_t start)
 {
@@ -126,32 +165,57 @@
     lc.cmd = LC_SEGMENT;
     /* Size is 1 segment command + 1 section command */
     lc.cmdsize = sizeof(lc) + sizeof(struct section);
+    /*
+     * Set the segment name.  This is very important because
+     * map_core_sections looks for segment command whose segment name
+     * matches a Lisp section name.
+     */
     strncpy(lc.segname, name, sizeof(lc.segname));
     lc.vmaddr = (uint32_t) start;
+    /*
+     * The size is very important.  map_core_sections uses this to
+     * determine how much to map.
+     */
     lc.vmsize = length;
-    /* Offset where the data is.  It's the header, the segment
-     * command, and one section */
+    /*
+     * Offset where the data is.  It's the header, the segment
+     * command, and one section.
+     */
     lc.fileoff = lc.cmdsize + sizeof(struct mach_header);
     lc.filesize = length;
     lc.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
     lc.initprot = lc.maxprot;
+    /* There's only one section for this segment command. */
     lc.nsects = 1;
     lc.flags = 0;
 
     return ewrite(fd, &lc, sizeof(lc), __func__);
 }
 
+/*
+ * Write the section info to the object file, fd.  Again, we need the
+ * object name (object_name) which is used as both the section name
+ * and the segment name.  The starting VM address (start) and the VM
+ * length (length) is needed for the section.
+ */
 static int
 write_section(int fd, int length, os_vm_address_t start, char* object_name)
 {
     struct section sc;
 
+    /*
+     * sectname and segname are the same for our purposes.  However,
+     * map_core_sections never looks here; it looks for the segment
+     * name from the segment commands.
+     */
     strncpy(sc.sectname, object_name, sizeof(sc.sectname));
     strncpy(sc.segname, object_name, sizeof(sc.segname));
     sc.addr = (uint32_t) start;
     sc.size = length;
-    /* Offset of the data.  We have one header, one segment and one
-     * section */
+    /*
+     * Offset of the data.  We have one header, one segment and one
+     * section
+     */
     sc.offset = sizeof(struct mach_header) + sizeof(struct segment_command) +
         sizeof(struct section);
     sc.align = 12;              /* Align on 2^12 = 4096 boundary */
@@ -164,12 +228,24 @@
     return ewrite(fd, &sc, sizeof(sc), __func__);
 }
 
+/*
+ * Write the actual data for the specific Lisp space to the object
+ * file.  The data is read from memory starting at real_addr and
+ * consists of length bytes.
+ */
+
 static int
 write_section_data(int fd, long length, os_vm_address_t real_addr)
 {
     return ewrite(fd, (void *)real_addr, length, __func__);
 }
 
+/*
+ * Write out an object file containing the data for our Lisp space.
+ * The object file is written to the directory dir.  The selected
+ * space is specified by id, and the starting address of the space is
+ * start, and goes to the address end.
+ */
 int
 write_space_object(const char *dir, int id, os_vm_address_t start, os_vm_address_t end)
 {
@@ -204,6 +280,9 @@
     return ret;
 }
 
+/*
+ * Remove the 3 space files that we created.
+ */
 void
 obj_cleanup(const char *dirname)
 {
@@ -218,6 +297,9 @@
     }
 }
 
+/*
+ * Link everything together to create the executable.
+ */
 int
 obj_run_linker(long init_func_address, char *file)
 {
@@ -292,7 +374,7 @@
 
 /*
  * Read the Mach-O header from a file descriptor and stuff it into a
- * structure.  Make sure it is really an elf header etc.
+ * structure.  Make sure it is really a Mach-O header etc.
  */
 static void
 read_mach_o_header(int fd, MachO_hdr *ehp)
Index: src/tools/linker-x86.sh
diff -u src/tools/linker-x86.sh:1.6 src/tools/linker-x86.sh:1.7
--- src/tools/linker-x86.sh:1.6	Fri Jul 30 22:55:17 2010
+++ src/tools/linker-x86.sh	Sun Aug  1 11:23:28 2010
@@ -1,16 +1,30 @@
 #!/bin/sh
 
-# $Id: linker-x86.sh,v 1.6 2010-07-31 02:55:17 rtoy Exp $
+# $Id: linker-x86.sh,v 1.7 2010-08-01 15:23:28 rtoy Exp $
 
 # This file written by Raymond Toy as part of CMU Common Lisp and is
 # placed in the public domain.
+#
+# This script takes parameters specified by the running lisp to create
+# an executable image.
+#
+# Despite the name, it is used for Linux/x86, Darwin/x86, and
+# Solaris/sparc, as specified in src/lisp/elf.h.
 
 OPSYS=`uname`
 
 if [ "X$CMU_DEBUG_LINKER" != "X" ]; then
+    # Enable debugging if CMU_DEBUG_LINKER is defined and not empty.
     set -x
 fi
 
+# There must be exactly 6 parameters:
+# - the name of the C compiler (sparc supports both Sun cc and GNU gcc).
+# - the address of the initial function (in C hex format)
+# - the path of the executable to be created
+# - the address of the start of the read-only space
+# - the address of the start of the static space
+# - the address of the start of the dynamic space
 if [ $# -ne 6 ]; then
     echo "Usage: `basename $0` <c-compiler> <initial-func-addr> <executable> <ro-addr> <static-addr> <dyn-addr>"
     exit 1
@@ -20,9 +34,12 @@
 IFADDR=$2
 EXEC=$3
 
+# Figure out the directory and file name of the executable.
 OUTDIR=`dirname $EXEC`
 OUTNAME=`basename $EXEC`
 
+# This tells us where the cmu lisp executable is and also the
+# locations of lisp.a.
 CMUCLLIB=`dirname $0`
 
 # Name of file where we write the actual initial function address.
@@ -33,6 +50,9 @@
 case `uname` in
   Linux*)
       # How to specify the starting address for each of the sections
+      # These aren't needed for Linux any more.  map_core_sections
+      # takes care of getting the addresses.
+
       #RO_ADDR="-Wl,--section-start=CORRO=$4"
       #STATIC_ADDR="-Wl,--section-start=CORSTA=$5"
       #DYN_ADDR="-Wl,--section-start=CORDYN=$6"
@@ -49,7 +69,12 @@
       OS_LIBS=-ldl
       ;;
   Darwin*)
-      # How to specify the starting address for each of the sections
+      # How to specify the starting address for each of the sections.
+      # We don't actually need these because map_core_sections sets
+      # the addresses itself instead of from the segment address, but
+      # if we don't set them up correctly, vmmap complains when run on
+      # the resulting executable.  There's no harm in specifying them
+      # here, though; the addresses are ignored by map_core_sections.
       RO_ADDR="-segaddr CORRO $4"
       STATIC_ADDR="-segaddr CORSTA $5"
       DYN_ADDR="-segaddr CORDYN $6"
@@ -76,9 +101,7 @@
       # Specify how to link the entire lisp.a library
       OPT_ARCHIVE="-Xlinker -z -Xlinker allextract -Xlinker $CMUCLLIB/lisp.a -Xlinker -z -Xlinker defaultextract"
 
-      # Extra stuff.  For some reason one __LINKEDIT segment is mapped
-      # just past the dynamic space.  This messes things up, so we move it
-      # to another address.  This seems to be free, at least on 10.5.
+      # Extra stuff.
 
       OPT_EXTRA="-Bdynamic"
 
@@ -88,6 +111,7 @@
 
 esac
 
+# Remove the C file when we're done.
 trap 'rm -f $OUTDIR/$OPT_IFADDR' 0
 
 (cd $OUTDIR



More information about the cmucl-commit mailing list