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