/[cmucl]/src/lisp/elf.c
ViewVC logotype

Contents of /src/lisp/elf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.32 - (show annotations)
Thu Dec 23 03:20:27 2010 UTC (3 years, 3 months ago) by rtoy
Branch: MAIN
CVS Tags: GIT-CONVERSION, snapshot-2011-09, snapshot-2011-06, snapshot-2011-07, snapshot-2011-04, snapshot-2011-02, snapshot-2011-03, snapshot-2011-01, HEAD
Changes since 1.31: +2 -2 lines
File MIME type: text/plain
Add support for NetBSD for the new executable image implementation.

lisp/Config_x86_netbsd:
o Define EXEC_FINAL_OBJ, like other x86 ports.

lisp/elf.c:
o Use the new linker.sh command script to link the executable.

lisp/lisp.c:
o Use new method of getting the initial_function.
1 /*
2
3 This code was written by Fred Gilham, and has been placed in the public
4 domain. It is provided "as-is" and without warranty of any kind.
5
6 Modified to add elf write code for writing out executables using
7 (save-lisp). FMG 27-Aug-2003
8
9 Above changes put into main CVS branch. 05-Jul-2007.
10
11 $Id: elf.c,v 1.32 2010/12/23 03:20:27 rtoy Exp $
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <fcntl.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21
22 #include "os.h"
23 #include "core.h"
24 #include "internals.h"
25 #include "globals.h"
26 #include "elf.h"
27 #include "validate.h"
28
29 static char elf_magic_string[] = {ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3};
30
31 /* Elf data structures. */
32 static Elf_Ehdr eh;
33 static Elf_Shdr sh;
34
35 /* Names of the Lisp image ELF sections. These names must be the same as
36 the corresponding names found in the linker script. */
37
38 static char *section_names[] = {"CORDYN", "CORSTA", "CORRO"};
39
40 /*
41 * Starting address of the three ELF sections/spaces. These must be
42 * in the same order as section_names above!
43 *
44 * XXX: Should we combine these into a structure? Should we do this
45 * for all architectures?
46 */
47 static os_vm_address_t section_addr[] =
48 {
49 (os_vm_address_t) DYNAMIC_0_SPACE_START,
50 (os_vm_address_t) STATIC_SPACE_START,
51 (os_vm_address_t) READ_ONLY_SPACE_START
52 };
53
54 /* Note: write errors are not fatal. */
55 static int
56 ewrite(int fd, const void *buf, size_t nbytes, const char *func)
57 {
58 if (write(fd, buf, nbytes) < nbytes) {
59 perror(func);
60 return -1; /* Simple way to indicate error. */
61 }
62 return 0;
63 }
64
65 /*
66 Read errors are fatal, because these reads have to succeed for lisp to
67 get off the ground.
68 */
69 static void
70 eread(int d, void *buf, size_t nbytes, const char *func)
71 {
72 int res = read(d, buf, nbytes);
73
74 if (res == -1) {
75 perror(func);
76 exit(-1);
77 }
78
79 if (res < nbytes) {
80 fprintf(stderr, "Short read in %s!\n", func);
81 exit(-1);
82 }
83 }
84
85 static void
86 elseek(int d, off_t o, const char *func)
87 {
88 if (lseek(d, o, SEEK_SET) == -1) {
89 perror(func);
90 exit(-1);
91 }
92 }
93
94
95 static int
96 create_elf_file (const char *dir, int id)
97 {
98 char outfilename[FILENAME_MAX + 1];
99 int out;
100
101 /* Note: the space id will be either 1, 2 or 3. Subtract one to index
102 the name array. */
103 snprintf(outfilename, FILENAME_MAX, "%s/%s.o", dir, section_names[id - 1]);
104 out = open(outfilename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
105
106 if(!out) {
107 perror("write_elf_object: can't open file");
108 fprintf(stderr, "%s\n", outfilename);
109 }
110
111 return out;
112 }
113
114
115 static int
116 write_elf_header(int fd)
117 {
118 extern Elf_Ehdr eh;
119
120 /* Ident array. */
121 eh.e_ident[EI_MAG0] = ELFMAG0;
122 eh.e_ident[EI_MAG1] = ELFMAG1;
123 eh.e_ident[EI_MAG2] = ELFMAG2;
124 eh.e_ident[EI_MAG3] = ELFMAG3;
125
126 eh.e_ident[EI_CLASS] = ELFCLASS32;
127 #if defined(sparc) && defined(SOLARIS)
128 eh.e_ident[EI_DATA] = ELFDATA2MSB;
129 #else
130 eh.e_ident[EI_DATA] = ELFDATA2LSB;
131 #endif
132 eh.e_ident[EI_VERSION] = EV_CURRENT;
133 #ifdef SOLARIS
134 eh.e_ident[EI_OSABI] = ELFOSABI_SOLARIS;
135 #else
136 eh.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
137 #endif
138
139 #ifdef SOLARIS
140 eh.e_type = ET_REL; /* ???? */
141 #else
142 eh.e_type = ET_NONE; /* ???? */
143 #endif
144 #if defined(sparc) && defined(SOLARIS)
145 /*
146 * We only support 32-bit code right now, and our binaries are
147 * v8plus binaries.
148 */
149 eh.e_machine = EM_SPARC32PLUS;
150 #else
151 eh.e_machine = EM_386;
152 #endif
153 eh.e_version = EV_CURRENT;
154 eh.e_entry = 0;
155 eh.e_phoff = 0;
156 eh.e_shoff = sizeof(Elf_Ehdr);
157 eh.e_flags = 0;
158 eh.e_ehsize = sizeof(Elf_Ehdr);
159 eh.e_phentsize = 0;
160 eh.e_phnum = 0;
161 eh.e_shentsize = sizeof(Elf_Shdr);
162 eh.e_shnum = 3; /* Number of lisp spaces. */
163 eh.e_shstrndx = 2;
164
165 return ewrite(fd, &eh, sizeof(Elf_Ehdr), __func__);
166 }
167
168
169 static int
170 write_zero_section_header(int fd)
171 {
172 /* Section index 0. */
173 sh.sh_name = 0;
174 sh.sh_type = SHT_NULL;
175 sh.sh_flags = 0;
176 sh.sh_addr = 0;
177 sh.sh_offset = 0;
178 sh.sh_size = 0;
179 sh.sh_link = SHN_UNDEF;
180 sh.sh_info = 0;
181 sh.sh_addralign = 0;
182 sh.sh_entsize = 0;
183
184 return ewrite(fd, &sh, eh.e_shentsize, __func__);
185 }
186
187
188 static char *string_table_name = ".shstrtab";
189 static char *object_name;
190
191 static int
192 write_object_section_header(int fd, long length, os_vm_address_t addr)
193 {
194 extern Elf_Shdr sh;
195 Elf_Word flags = SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE;
196
197 sh.sh_name = strlen(string_table_name) + 2;
198 sh.sh_type = SHT_PROGBITS;
199 sh.sh_flags = flags;
200 sh.sh_addr = (Elf_Addr)addr;
201
202 /* The object section offset is figured out as follows: elf-header +
203 three section headers + string table. The string table is the
204 initial null byte followed by the name strings for the string
205 table section and the object section. */
206 sh.sh_offset = sizeof(Elf_Ehdr) + 3 * sizeof(Elf_Shdr) + 1 +
207 (strlen(string_table_name) + 1) + (strlen(object_name) + 1);
208 sh.sh_size = length;
209 sh.sh_link = SHN_UNDEF;
210 sh.sh_info = 0;
211 sh.sh_addralign = os_vm_page_size; /* Must be page aligned. */
212 sh.sh_entsize = 0;
213
214 return ewrite(fd, &sh, eh.e_shentsize, __func__);
215 }
216
217
218 static int
219 write_string_section_header(int fd)
220 {
221 /* Section index 0. */
222
223 extern Elf_Shdr sh;
224
225 sh.sh_name = 1;
226 sh.sh_type = SHT_STRTAB;
227 sh.sh_flags = 0;
228 sh.sh_addr = 0;
229 sh.sh_offset = sizeof(Elf_Ehdr) + 3 * sizeof(Elf_Shdr);
230 /* The size of this section is the lengths of the strings plus the
231 nulls. */
232 sh.sh_size = strlen(string_table_name) + strlen(object_name) + 3;
233 sh.sh_link = SHN_UNDEF;
234 sh.sh_info = 0;
235 sh.sh_addralign = 0;
236 sh.sh_entsize = 0;
237
238 return ewrite(fd, &sh, eh.e_shentsize, __func__);
239 }
240
241
242 static int
243 write_string_section(int fd)
244 {
245 char *buffer = malloc(1 + strlen(string_table_name) + 1 +
246 strlen(object_name) + 1);
247 int ret;
248
249 if(buffer == NULL) {
250
251 write(0, "Out of memory in write_string_section()\n", 40);
252 ret = -1;
253
254 } else {
255
256 *buffer = '\0';
257 memcpy(buffer + 1, string_table_name, strlen(string_table_name) + 1);
258 memcpy(buffer + 1 + strlen(string_table_name) + 1,
259 object_name,
260 strlen(object_name) + 1);
261 ret = ewrite(fd, buffer,
262 1 + strlen(string_table_name) + 1 + strlen(object_name) + 1,
263 __func__);
264 free(buffer);
265 }
266
267 return ret;
268 }
269
270
271 static int
272 write_object_section(int fd, long length, os_vm_address_t real_addr)
273 {
274 return ewrite(fd, (void *)real_addr, length, __func__);
275 }
276
277
278 int
279 write_space_object(const char *dir, int id, os_vm_address_t start, os_vm_address_t end)
280 {
281 int out = create_elf_file(dir, id);
282 int ret = 0;
283 /* The length should be a multiple of the page size. */
284 size_t length = end - start + (os_vm_page_size -
285 ((end - start) % os_vm_page_size));
286 static char *names[] = { "Dynamic", "Static", "Read-Only" };
287
288 if(id < 1 || id > 3) {
289 fprintf(stderr, "Invalid space id in %s: %d\n", __func__, id);
290 fprintf(stderr, "Executable not built.\n");
291 ret = -1;
292 }
293
294 /* Make id be 0-based to match array. */
295 id--;
296
297 object_name = section_names[id];
298
299 printf("\t %s: %d bytes...\n", names[id], (end - start));
300 fflush(stdout);
301
302 if ((write_elf_header(out) == -1) ||
303 (write_zero_section_header(out) == -1) ||
304 (write_object_section_header(out, length, start) == -1) ||
305 (write_string_section_header(out) == -1) ||
306 (write_string_section(out) == -1) ||
307 (write_object_section(out, length, start) == -1)) {
308 fprintf(stderr, "Executable not built.\n");
309 ret = -1;
310 }
311
312 close(out);
313 return ret;
314 }
315
316 int
317 obj_run_linker(long init_func_address, char *file)
318 {
319 lispobj libstring = SymbolValue(CMUCL_LIB); /* Get library: */
320 struct vector *vec = (struct vector *)PTR(libstring);
321 char *paths;
322 char command[FILENAME_MAX + 1];
323 char command_line[FILENAME_MAX + FILENAME_MAX + 10];
324 char *strptr;
325 struct stat st;
326 int ret;
327 extern int debug_lisp_search;
328 #ifndef UNICODE
329 paths = strdup((char *)vec->data);
330 #else
331 /*
332 * What should we do here with 16-bit characters? For now we just
333 * take the low 8-bits.
334 */
335 paths = malloc(vec->length);
336 {
337 int k;
338 unsigned short *data;
339 data = (unsigned short*) vec->data;
340
341 for (k = 0; k < vec->length; ++k) {
342 paths[k] = data[k] & 0xff;
343 }
344 }
345 #endif
346 strptr = strtok(paths, ":");
347
348 if (debug_lisp_search) {
349 printf("Searching for linker.sh script\n");
350 }
351
352 while(strptr != NULL) {
353
354 sprintf(command, "%s/%s", strptr, LINKER_SCRIPT);
355
356 if (debug_lisp_search) {
357 printf(" %s\n", command);
358 }
359
360 if (stat(command, &st) == 0) {
361 free(paths);
362 printf("\t[%s: linking %s... \n", command, file);
363 fflush(stdout);
364 #if defined(__linux__) || defined(__FreeBSD__) || defined(SOLARIS) || defined(__NetBSD__)
365 sprintf(command_line, "%s %s 0x%lx '%s' 0x%lx 0x%lx 0x%lx", command,
366 C_COMPILER, init_func_address, file,
367 (unsigned long) READ_ONLY_SPACE_START,
368 (unsigned long) STATIC_SPACE_START,
369 (unsigned long) DYNAMIC_0_SPACE_START);
370 #else
371 extern int main();
372 sprintf(command_line, "%s %s 0x%lx 0x%lx %s", command, C_COMPILER,
373 init_func_address, (unsigned long) &main, file);
374 #endif
375 ret = system(command_line);
376 if(ret == -1) {
377 perror("Can't run link script");
378 } else {
379 printf("\tdone]\n");
380 fflush(stdout);
381 }
382 return ret;
383 }
384 strptr = strtok(NULL, ":");
385 }
386
387 fprintf(stderr,
388 "Can't find %s script in CMUCL library directory list.\n", LINKER_SCRIPT);
389 free(paths);
390 return -1;
391 }
392
393
394 /* Read the ELF header from a file descriptor and stuff it into a
395 structure. Make sure it is really an elf header etc. */
396 static void
397 read_elf_header(int fd, Elf_Ehdr *ehp)
398 {
399 eread(fd, ehp, sizeof(Elf_Ehdr), __func__);
400
401 if (strncmp((const char *) ehp->e_ident, elf_magic_string, 4)) {
402 fprintf(stderr,
403 "Bad ELF magic number --- not an elf file. Exiting in %s.\n",
404 __func__);
405 exit(-1);
406 }
407 }
408
409
410 static void
411 read_section_header_entry(int fd, Elf_Shdr *shp)
412 {
413 eread(fd, shp, eh.e_shentsize, __func__);
414 }
415
416
417 /*
418 Map the built-in lisp core sections.
419
420 NOTE! We need to do this without using malloc because the memory layout
421 is not set until some time after this is done.
422 */
423 void
424 map_core_sections(const char *exec_name)
425 {
426 int exec_fd;
427 Elf_Shdr sh; /* A section header entry. */
428 Elf_Shdr strsecent;
429 char nambuf[10];
430 int soff;
431 int strsecoff; /* File offset to string table section. */
432 int sections_remaining = 3;
433 int i, j;
434 extern int
435 image_dynamic_space_size,
436 image_static_space_size,
437 image_read_only_space_size;
438
439 if (!(exec_fd = open(exec_name, O_RDONLY))) {
440 perror("Can't open executable!");
441 exit(-1);
442 }
443
444 read_elf_header(exec_fd, &eh);
445
446 /* Find the section name string section. Save its file offset. */
447 soff = eh.e_shoff + eh.e_shstrndx * eh.e_shentsize;
448 elseek(exec_fd, soff, __func__);
449 read_section_header_entry(exec_fd, &strsecent);
450 strsecoff = strsecent.sh_offset;
451
452 for (i = 0; i < eh.e_shnum && sections_remaining > 0; i++) {
453
454 /* Read an entry from the section header table. */
455 elseek(exec_fd, eh.e_shoff + i * eh.e_shentsize, __func__);
456 read_section_header_entry(exec_fd, &sh);
457
458 /* Read the name from the string section. */
459 elseek(exec_fd, strsecoff + sh.sh_name, __func__);
460 eread(exec_fd, nambuf, 6, __func__);
461
462 if (sh.sh_type == SHT_PROGBITS) {
463 /* See if this section is one of the lisp core sections. */
464 for (j = 0; j < 3; j++) {
465 if (!strncmp(nambuf, section_names[j], 6)) {
466 os_vm_address_t addr;
467 /*
468 * Found a core section. Map it!
469 *
470 * Although the segment may contain the correct
471 * address for the start of the segment, we don't
472 * care. We infer the address from the segment
473 * name. (The names better be unique!!!!) This
474 * approach allows for a possibly simpler linking
475 * operation because we don't have to figure out
476 * how to get the linker to give segments the
477 * correct address.
478 */
479 addr = section_addr[j];
480 if ((os_vm_address_t) os_map(exec_fd, sh.sh_offset,
481 addr, sh.sh_size)
482 == (os_vm_address_t) -1) {
483 fprintf(stderr, "%s: Can't map section %s\n", __func__, section_names[j]);
484 exit(-1);
485 }
486 switch(j) {
487 case 0: /* Dynamic space. */
488 /* Dynamic space variables are set in lisp.c. */
489 image_dynamic_space_size = sh.sh_size;
490 break;
491 case 1: /* Static space. */
492 image_static_space_size = sh.sh_size;
493 break;
494 case 2: /* Read-only space. */
495 image_read_only_space_size = sh.sh_size;
496 break;
497 default:
498 /* Should never get here. */
499 abort();
500 break;
501 }
502
503 sections_remaining--;
504 /* Found a core section, don't check the other core section names. */
505 break;
506 }
507 }
508 }
509 }
510
511 close(exec_fd);
512
513 if (sections_remaining != 0) {
514 fprintf(stderr, "Couldn't map all core sections! Exiting!\n");
515 exit(-1);
516 }
517 }

  ViewVC Help
Powered by ViewVC 1.1.5