From 5634f3f848c1170ccbd060618f369c6bcd1dd545 Mon Sep 17 00:00:00 2001 From: rtoy <rtoy> Date: Sun, 1 Aug 2010 15:23:28 +0000 Subject: [PATCH] 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(-) diff --git a/lisp/mach-o.c b/lisp/mach-o.c index 25239464b..759320af9 100644 --- a/lisp/mach-o.c +++ b/lisp/mach-o.c @@ -1,3 +1,22 @@ +/* + * $Header: /Volumes/share2/src/cmucl/cvs2git/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 @@ elseek(int d, off_t o, int whence, const char *func) } } +/* + * 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 @@ create_mach_o_file (const char *dir, int id) 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 @@ write_mach_o_header(int fd) /* 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 @@ write_mach_o_header(int fd) 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 @@ write_load_command(int fd, char* name, int length, os_vm_address_t start) 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 @@ write_section(int fd, int length, os_vm_address_t start, char* object_name) 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 @@ write_space_object(const char *dir, int id, os_vm_address_t start, os_vm_address return ret; } +/* + * Remove the 3 space files that we created. + */ void obj_cleanup(const char *dirname) { @@ -218,6 +297,9 @@ obj_cleanup(const char *dirname) } } +/* + * Link everything together to create the executable. + */ int obj_run_linker(long init_func_address, char *file) { @@ -292,7 +374,7 @@ obj_run_linker(long init_func_address, char *file) /* * 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) diff --git a/tools/linker-x86.sh b/tools/linker-x86.sh index 65ad00dcf..82ae8cd01 100644 --- a/tools/linker-x86.sh +++ b/tools/linker-x86.sh @@ -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 @@ CCOMPILER=$1 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 @@ OPT_CORE="CORRO.o CORSTA.o CORDYN.o" 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 @@ case `uname` in 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 @@ case `uname` in # 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 @@ case `uname` in esac +# Remove the C file when we're done. trap 'rm -f $OUTDIR/$OPT_IFADDR' 0 (cd $OUTDIR -- GitLab