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