441358ed3df0363cbff7d2ad444f0e5efafe7e47
[projects/cmucl/cmucl.git] / src / lisp / mach-o.c
1 /*
2  * $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/mach-o.c,v 1.7 2010/08/02 21:59:43 rtoy Rel $
3  *
4  * This code was written by Raymond Toy as part of CMU Common Lisp and
5  * has been placed in the public domain.
6  *
7  * Mach-O support for generating executable images on Mac OS X (aka
8  * Darwin).  This only knows enough of the Mach-O format to be able to
9  * write out very simple object files for the Lisp spaces and to read
10  * just enough of a Mach-O executable to find the segments containing
11  * the Lisp spaces.
12  *
13  * For details of the file format see " Mac OS X ABI Mach-O File
14  * Format Reference",
15  * http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
16  *
17  * 
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include "os.h"
29 #include "core.h"
30 #include "internals.h"
31 #include "globals.h"
32 #include "validate.h"
33
34 #include "elf.h"
35
36 typedef struct mach_header MachO_hdr;
37
38 /* Uncomment to enable debugging prints */
39 /* #define DEBUG_MACH_O */
40
41 /*
42  * Names of the Lisp image sections. These names must be the same as
43  * the corresponding names found in the linker script.
44  */
45
46 static char *section_names[] = {"CORDYN", "CORSTA", "CORRO"};
47
48 /*
49  * Starting addresses of the various spaces.  Must be in the same
50  * order as section_names
51  */
52 static os_vm_address_t section_addr[] =
53 {
54     (os_vm_address_t) DYNAMIC_0_SPACE_START,
55     (os_vm_address_t) STATIC_SPACE_START,
56     (os_vm_address_t) READ_ONLY_SPACE_START
57 };
58
59 /* Note: write errors are not fatal. */
60 static int
61 ewrite(int fd, const void *buf, size_t nbytes, const char *func)
62 {
63     if (write(fd, buf, nbytes) < nbytes) {
64         perror(func);
65         return -1;      /* Simple way to indicate error. */
66     }
67     return 0;
68 }
69
70 /*
71   Read errors are fatal, because these reads have to succeed for lisp to
72   get off the ground.
73  */
74 static void
75 eread(int d, void *buf, size_t nbytes, const char *func)
76 {
77     int res = read(d, buf, nbytes);
78
79     if (res == -1) {
80         perror(func);
81         exit(-1);
82     }
83
84     if (res < nbytes) {
85         fprintf(stderr, "Short read in %s!\n", func);
86         exit(-1);
87     }
88 }
89
90 static void
91 elseek(int d, off_t o, int whence, const char *func)
92 {
93     if (lseek(d, o, whence) == -1) {
94         perror(func);
95         exit(-1);
96     }
97 }
98
99 /*
100  * Create a file for the specified Lisp space in the specified
101  * directory.
102  */
103 static int
104 create_mach_o_file (const char *dir, int id)
105 {
106     char outfilename[FILENAME_MAX + 1];
107     int out;
108
109     /* Note: the space id will be either 1, 2 or 3.  Subtract one to index
110        the name array. */
111     snprintf(outfilename, FILENAME_MAX, "%s/%s.o", dir, section_names[id - 1]);
112     out = open(outfilename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
113
114     if(!out) {
115         perror("create_mach_o_file: can't open file");
116         fprintf(stderr, "%s\n", outfilename);
117     }
118
119     return out;
120 }
121
122 /*
123  * Write the Mach-O header.  We only handle what we need for our
124  * purposes.
125  */
126 static int
127 write_mach_o_header(int fd)
128 {
129     MachO_hdr eh;
130
131     /* Ident array. */
132     eh.magic = MH_MAGIC;
133 #if defined(__ppc__)
134     eh.cputype = CPU_TYPE_POWERPC;
135     eh.cpusubtype = CPU_SUBTYPE_POWERPC_ALL;
136 #else
137     eh.cputype = CPU_TYPE_I386;
138     /*
139      * Support any kind x86.  Should we be more specific?  We need at
140      * least a pentium to run x87.  For SSE2 we need at least a
141      * Pentium 4 chip.  So if the core is SSE2, should we set this to
142      * Pentium 4?
143      */
144     eh.cpusubtype = CPU_SUBTYPE_I386_ALL;
145 #endif
146
147     eh.filetype = MH_OBJECT;
148
149     /* We only have 1 load command in our object */
150     eh.ncmds = 1;
151     /* Size of 1 segment command plus size of 1 section */
152     eh.sizeofcmds = sizeof(struct segment_command) + sizeof(struct section);
153     eh.flags = MH_NOUNDEFS | MH_NOMULTIDEFS;
154
155     return ewrite(fd, &eh, sizeof(MachO_hdr), __func__);
156 }
157
158 /*
159  * Write one segment (load) command to the object file in fd.  The
160  * name of the segment is in name.  We also need to specify the
161  * starting VM address (start) and the VM size (length) of the section
162  * of memory that we want this to map to.
163  */
164 static int
165 write_load_command(int fd, char* name, int length, os_vm_address_t start)
166 {
167     struct segment_command lc;
168
169     lc.cmd = LC_SEGMENT;
170     /* Size is 1 segment command + 1 section command */
171     lc.cmdsize = sizeof(lc) + sizeof(struct section);
172     /*
173      * Set the segment name.  This is very important because
174      * map_core_sections looks for segment command whose segment name
175      * matches a Lisp section name.
176      */
177     strncpy(lc.segname, name, sizeof(lc.segname));
178     lc.vmaddr = (uint32_t) start;
179     /*
180      * The size is very important.  map_core_sections uses this to
181      * determine how much to map.
182      */
183     lc.vmsize = length;
184     /*
185      * Offset where the data is.  It's the header, the segment
186      * command, and one section.
187      */
188     lc.fileoff = lc.cmdsize + sizeof(struct mach_header);
189     lc.filesize = length;
190     lc.maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE;
191     lc.initprot = lc.maxprot;
192     /* There's only one section for this segment command. */
193     lc.nsects = 1;
194     lc.flags = 0;
195
196     return ewrite(fd, &lc, sizeof(lc), __func__);
197 }
198
199 /*
200  * Write the section info to the object file, fd.  Again, we need the
201  * object name (object_name) which is used as both the section name
202  * and the segment name.  The starting VM address (start) and the VM
203  * length (length) is needed for the section.
204  */
205 static int
206 write_section(int fd, int length, os_vm_address_t start, char* object_name)
207 {
208     struct section sc;
209
210     /*
211      * sectname and segname are the same for our purposes.  However,
212      * map_core_sections never looks here; it looks for the segment
213      * name from the segment commands.
214      */
215     strncpy(sc.sectname, object_name, sizeof(sc.sectname));
216     strncpy(sc.segname, object_name, sizeof(sc.segname));
217     sc.addr = (uint32_t) start;
218     sc.size = length;
219     /*
220      * Offset of the data.  We have one header, one segment and one
221      * section
222      */
223     sc.offset = sizeof(struct mach_header) + sizeof(struct segment_command) +
224         sizeof(struct section);
225     sc.align = 12;              /* Align on 2^12 = 4096 boundary */
226     sc.reloff = 0;
227     sc.nreloc = 0;
228     sc.flags = 0;
229     sc.reserved1 = 0;
230     sc.reserved2 = 0;
231
232     return ewrite(fd, &sc, sizeof(sc), __func__);
233 }
234
235 /*
236  * Write the actual data for the specific Lisp space to the object
237  * file.  The data is read from memory starting at real_addr and
238  * consists of length bytes.
239  */
240
241 static int
242 write_section_data(int fd, long length, os_vm_address_t real_addr)
243 {
244     return ewrite(fd, (void *)real_addr, length, __func__);
245 }
246
247 /*
248  * Write out an object file containing the data for our Lisp space.
249  * The object file is written to the directory dir.  The selected
250  * space is specified by id, and the starting address of the space is
251  * start, and goes to the address end.
252  */
253 int
254 write_space_object(const char *dir, int id, os_vm_address_t start, os_vm_address_t end)
255 {
256     int out = create_mach_o_file(dir, id);
257     int ret = 0;
258     /* The length should be a multiple of the page size. */
259     size_t length = end - start + (os_vm_page_size -
260                                    ((end - start) % os_vm_page_size));
261     static char *names[] = { "Dynamic", "Static", "Read-Only" };
262
263     if(id < 1 || id > 3) {
264         fprintf(stderr, "Invalid space id in %s: %d\n", __func__, id);
265         fprintf(stderr, "Executable not built.\n");
266         ret = -1;
267     }
268
269     /* Make id be 0-based to match array. */
270     id--;
271
272     printf("\t %s: %d bytes...\n", names[id], (end - start));
273     fflush(stdout);
274
275     if ((write_mach_o_header(out) == -1)
276         || (write_load_command(out, section_names[id], length, start) == -1)
277         || (write_section(out, length, start, section_names[id]) == -1)
278         || (write_section_data(out, length, start) == -1)) {
279         fprintf(stderr, "Executable not built.\n");
280         ret = -1;
281     }
282
283     close(out);
284     return ret;
285 }
286
287 /*
288  * Link everything together to create the executable.
289  */
290 int
291 obj_run_linker(long init_func_address, char *file)
292 {
293     lispobj libstring = SymbolValue(CMUCL_LIB);     /* Get library: */
294     struct vector *vec = (struct vector *)PTR(libstring);
295     char *paths;
296     char command[FILENAME_MAX + 1];
297     char command_line[FILENAME_MAX + FILENAME_MAX + 10];
298     char *strptr;
299     struct stat st;
300     int ret;
301     extern int debug_lisp_search;
302 #ifndef UNICODE
303     paths = strdup((char *)vec->data);
304 #else
305     /*
306      * What should we do here with 16-bit characters?  For now we just
307      * take the low 8-bits.
308      */
309     paths = malloc(vec->length);
310     {
311         int k;
312         unsigned short *data;
313         data = (unsigned short*) vec->data;
314         
315         for (k = 0; k < vec->length; ++k) {
316             paths[k] = data[k] & 0xff;
317         }
318     }
319 #endif
320     strptr = strtok(paths, ":");
321
322     if (debug_lisp_search) {
323         printf("Searching for %s script\n", LINKER_SCRIPT);
324     }
325
326     while(strptr != NULL) {
327         
328         sprintf(command, "%s/%s", strptr, LINKER_SCRIPT);
329
330         if (debug_lisp_search) {
331             printf("  %s\n", command);
332         }
333         
334         if (stat(command, &st) == 0) {
335             free(paths);
336             printf("\t[%s: linking %s... \n", command, file);
337             fflush(stdout);
338             sprintf(command_line, "%s %s 0x%lx '%s' 0x%lx 0x%lx 0x%lx", command,
339                     C_COMPILER, init_func_address, file,
340                     (unsigned long) READ_ONLY_SPACE_START,
341                     (unsigned long) STATIC_SPACE_START,
342                     (unsigned long) DYNAMIC_0_SPACE_START);
343             ret = system(command_line);
344             if (ret == -1) {
345                 perror("Can't run link script");
346             } else {
347                 printf("\tdone]\n");
348                 fflush(stdout);
349             }
350             return ret;
351         }
352         strptr = strtok(NULL, ":");
353     }
354
355     fprintf(stderr,
356             "Can't find %s script in CMUCL library directory list.\n", LINKER_SCRIPT);
357     free(paths);
358     return -1;
359 }
360
361
362 /*
363  * Read the Mach-O header from a file descriptor and stuff it into a
364  * structure.  Make sure it is really a Mach-O header etc.
365  */
366 static void
367 read_mach_o_header(int fd, MachO_hdr *ehp)
368 {
369     eread(fd, ehp, sizeof(MachO_hdr), __func__);
370
371     if (ehp->magic != MH_MAGIC) {
372         fprintf(stderr,
373                 "Bad Mach-O magic number --- not a Mach-O file. Exiting in %s.\n",
374                 __func__);
375         exit(-1);
376     }
377 }
378
379
380 /*
381  * Map the built-in lisp core sections.
382  *
383  * NOTE!  We need to do this without using malloc because the memory
384  * layout is not set until some time after this is done.
385  */
386 void
387 map_core_sections(const char *exec_name)
388 {
389     MachO_hdr eh;
390     int exec_fd;
391     int sections_remaining = 3;
392     int i;
393     int j;
394     extern int image_dynamic_space_size;
395     extern int image_static_space_size;
396     extern int image_read_only_space_size;
397
398     if (!(exec_fd = open(exec_name, O_RDONLY))) {
399         perror("Can't open executable!");
400         exit(-1);
401     }
402
403     read_mach_o_header(exec_fd, &eh);
404
405     for (i = 0; i < eh.ncmds && sections_remaining > 0; i++) {
406         struct load_command lc;
407         struct segment_command sc;
408         
409         /*
410          * Read the load command to see what kind of command it is and
411          * how big it is.
412          */
413         
414         eread(exec_fd, &lc, sizeof(lc), __func__);
415 #ifdef DEBUG_MACH_O
416         fprintf(stderr, "Load %d:  cmd = %d, cmdsize = %d\n", i, lc.cmd, lc.cmdsize);
417 #endif
418
419         if (lc.cmd == LC_SEGMENT) {
420           /*
421            * Got a segment command, so read the rest of the command so
422            * we can see if it's the segment for one of our Lisp
423            * spaces.
424            */
425 #ifdef DEBUG_MACH_O
426             fprintf(stderr, "Reading next %ld bytes for SEGMENT\n", sizeof(sc) - sizeof(lc));
427 #endif
428
429             eread(exec_fd, &sc.segname, sizeof(sc) - sizeof(lc), __func__);
430
431 #ifdef DEBUG_MACH_O
432             fprintf(stderr, "LC_SEGMENT: name = %s\n", sc.segname);
433 #endif
434
435             /* See if the segment name matches any of our section names */
436             for (j = 0; j < 3; ++j) {
437                 if (strncmp(sc.segname, section_names[j], sizeof(sc.segname)) == 0) {
438                     os_vm_address_t addr;
439
440                     /* Found a core segment.  Map it! */
441 #ifdef DEBUG_MACH_O
442                     fprintf(stderr, "Matched!\n");
443                     fprintf(stderr, " Fileoff = %u\n", sc.fileoff);
444                     fprintf(stderr, " vmaddr  = 0x%x\n", sc.vmaddr);
445                     fprintf(stderr, " vmsize  = 0x%x\n", sc.vmsize);
446 #endif
447                     /*
448                      * We don't care what address the segment has.  We
449                      * will map it where want it to go.
450                      */
451                     
452                     addr = section_addr[j];
453                     
454                     if ((os_vm_address_t) os_map(exec_fd, sc.fileoff,
455                                                  (os_vm_address_t) addr,
456                                                  sc.vmsize)
457                         == (os_vm_address_t) -1) {
458                         fprintf(stderr, "%s: Can't map section %s\n", __func__, section_names[j]);
459                         exit(-1);
460                     }
461                     switch (j) {
462                       case 0:
463                           /* Dynamic space */
464                           image_dynamic_space_size = sc.vmsize;
465                           break;
466                       case 1:
467                           /* Static space */
468                           image_static_space_size = sc.vmsize;
469                           break;
470                       case 2:
471                           /* Read only */
472                           image_read_only_space_size = sc.vmsize;
473                           break;
474                       default:
475                           /* Shouldn't happen! */
476                           abort();
477                     }
478                     --sections_remaining;
479                     break;
480                 }
481             }
482 #ifdef DEBUG_MACH_O
483             fprintf(stderr, "Skipping %ld remainder bytes left in command\n",
484                     lc.cmdsize - sizeof(sc));
485 #endif
486             elseek(exec_fd, lc.cmdsize - sizeof(sc), SEEK_CUR, __func__);
487         } else {
488             /* Not a segment command, so seek to the next command */
489 #ifdef DEBUG_MACH_O
490             fprintf(stderr, "Seeking by %ld bytes\n", lc.cmdsize - sizeof(lc));
491 #endif
492             elseek(exec_fd, lc.cmdsize - sizeof(lc), SEEK_CUR, __func__);
493         }
494     }
495
496     close(exec_fd);
497
498     if (sections_remaining != 0) {
499         fprintf(stderr, "Couldn't map all core sections!        Exiting!\n");
500         exit(-1);
501     }
502 }