Accept "in" instance variables
[delight/core.git] / dmd / libelf.c
blob594b4f810e0e4953732dc91d2009c10887b66fc1
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <assert.h>
14 #include <time.h>
15 #include <unistd.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
19 #include "mem.h"
20 #include "root.h"
21 #include "stringtable.h"
23 #include "mars.h"
24 #include "lib.h"
25 #include "melf.h"
27 #define LOG 1
29 Library::Library()
31 libfile = NULL;
34 /***********************************
35 * Set the library file name based on the output directory
36 * and the filename.
37 * Add default library file name extension.
40 void Library::setFilename(char *dir, char *filename)
42 #if LOG
43 printf("Library::setFilename(dir = '%s', filename = '%s')\n",
44 dir ? dir : "", filename ? filename : "");
45 #endif
46 char *arg = filename;
47 if (!arg || !*arg)
48 { // Generate lib file name from first obj name
49 char *n = (char *)global.params.objfiles->data[0];
51 n = FileName::name(n);
52 FileName *fn = FileName::forceExt(n, global.lib_ext);
53 arg = fn->toChars();
55 if (!FileName::absolute(arg))
56 arg = FileName::combine(dir, arg);
57 FileName *libfilename = FileName::defaultExt(arg, global.lib_ext);
59 libfile = new File(libfilename);
62 void Library::write()
64 if (global.params.verbose)
65 printf("library %s\n", libfile->name->toChars());
67 OutBuffer libbuf;
68 WriteLibToBuffer(&libbuf);
70 // Transfer image to file
71 libfile->setbuffer(libbuf.data, libbuf.offset);
72 libbuf.extractData();
75 char *p = FileName::path(libfile->name->toChars());
76 FileName::ensurePathExists(p);
77 //mem.free(p);
79 libfile->writev();
82 /*****************************************************************************/
84 void Library::addLibrary(void *buf, size_t buflen)
86 addObject(NULL, buf, buflen);
90 /*****************************************************************************/
91 /*****************************************************************************/
93 static char elf[4] = { 0x7F, 'E', 'L', 'F' }; // ELF file signature
95 void sputl(int value, void* buffer)
97 unsigned char *p = (unsigned char*)buffer;
98 p[0] = (unsigned char)(value >> 24);
99 p[1] = (unsigned char)(value >> 16);
100 p[2] = (unsigned char)(value >> 8);
101 p[3] = (unsigned char)(value);
104 int sgetl(void* buffer)
106 unsigned char *p = (unsigned char*)buffer;
107 return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3];
111 struct ObjModule
113 unsigned char *base; // where are we holding it in memory
114 unsigned length; // in bytes
115 unsigned offset; // offset from start of library
116 char *name; // module name (file name)
117 int name_offset; // if not -1, offset into string table of name
118 long file_time; // file time
119 unsigned user_id;
120 unsigned group_id;
121 unsigned file_mode;
122 int scan; // 1 means scan for symbols
125 struct Header
127 #define OBJECT_NAME_SIZE 16
128 char object_name[OBJECT_NAME_SIZE];
129 char file_time[12];
130 char user_id[6];
131 char group_id[6];
132 char file_mode[8]; // in octal
133 char file_size[10];
134 char trailer[2];
137 void OmToHeader(Header *h, ObjModule *om)
139 size_t len;
140 if (om->name_offset == -1)
142 len = strlen(om->name);
143 memcpy(h->object_name, om->name, len);
144 h->object_name[len] = '/';
145 assert(len < OBJECT_NAME_SIZE);
146 memset(h->object_name + len + 1, ' ', OBJECT_NAME_SIZE - (len + 1));
148 else
150 len = sprintf(h->object_name, "/%d", om->name_offset);
151 h->object_name[len] = ' ';
154 /* In the following sprintf's, don't worry if the trailing 0
155 * that sprintf writes goes off the end of the field. It will
156 * write into the next field, which we will promptly overwrite
157 * anyway. (So make sure to write the fields in ascending order.)
160 len = sprintf(h->file_time, "%lu", om->file_time);
161 assert(len <= 12);
162 memset(h->file_time + len, ' ', 12 - len);
164 len = sprintf(h->user_id, "%u", om->user_id);
165 assert(len <= 6);
166 memset(h->user_id + len, ' ', 6 - len);
168 len = sprintf(h->group_id, "%u", om->group_id);
169 assert(len <= 6);
170 memset(h->group_id + len, ' ', 6 - len);
172 len = sprintf(h->file_mode, "%o", om->file_mode);
173 assert(len <= 8);
174 memset(h->file_mode + len, ' ', 8 - len);
176 len = sprintf(h->file_size, "%u", om->length);
177 assert(len <= 10);
178 memset(h->file_size + len, ' ', 10 - len);
180 h->trailer[0] = '`';
181 h->trailer[1] = '\n';
184 void Library::addSymbol(ObjModule *om, char *name, int pickAny)
186 #if LOG
187 printf("Library::addSymbol(%s, %s, %d)\n", om->name, name, pickAny);
188 #endif
189 StringValue *s = tab.insert(name, strlen(name));
190 if (!s)
191 { // already in table
192 if (!pickAny)
193 { s = tab.lookup(name, strlen(name));
194 assert(s);
195 ObjSymbol *os = (ObjSymbol *)s->ptrvalue;
196 error("multiple definition of %s: %s and %s: %s",
197 om->name, name, os->om->name, os->name);
200 else
202 ObjSymbol *os = new ObjSymbol();
203 os->name = strdup(name);
204 os->om = om;
205 s->ptrvalue = (void *)os;
207 objsymbols.push(os);
211 /************************************
212 * Scan single object module for dictionary symbols.
213 * Send those symbols to Library::addSymbol().
216 void Library::scanObjModule(ObjModule *om)
218 #if LOG
219 printf("Library::scanObjModule(%s)\n", om->name);
220 #endif
221 unsigned char *buf = (unsigned char *)om->base;
222 size_t buflen = om->length;
223 int reason = 0;
225 if (buflen < sizeof(elf_header_f32))
227 Lcorrupt:
228 error("corrupt ELF object module %s %d", om->name, reason);
229 return;
232 elf_header_f32 *eh = (elf_header_f32 *)buf;
233 if (memcmp(buf, elf, 4))
234 { reason = 1;
235 goto Lcorrupt;
237 if (eh->EHtype != EH_TYPE_RELFILE)
238 return; // not relocatable object module
240 #if 0
241 /* String table section
243 elf_sht *string_section = (elf_sht *)(buf + eh->EHshtoff +
244 eh->EHshtentsz * eh->EHshtstrndx);
245 if (string_section->SHtype != SHT_STRTAB)
247 //printf("buf = %p, EHshtentsz = %d, EHshtstrndx = %d\n", buf, eh->EHshtentsz, eh->EHshtstrndx);
248 //printf("SHtype = %d, SHT_STRTAB = %d\n", string_section->SHtype, SHT_STRTAB);
249 reason = 2;
250 goto Lcorrupt;
252 printf("strtab SHfileoff = x%x\n", string_section->SHfileoff);
253 char *string_tab = (char *)(buf + string_section->SHfileoff);
254 #endif
256 /* For each Section
258 for (unsigned u = 0; u < eh->EHshtnum; u++)
259 { elf_sht *section = (elf_sht *)(buf + eh->EHshtoff + eh->EHshtentsz * u);
261 if (section->SHtype == SHT_SYMTAB)
262 { /* SHoptidx gives the particular string table section
263 * used for the symbol names.
265 elf_sht *string_section = (elf_sht *)(buf + eh->EHshtoff +
266 eh->EHshtentsz * section->SHoptidx);
267 if (string_section->SHtype != SHT_STRTAB)
269 reason = 3;
270 goto Lcorrupt;
272 char *string_tab = (char *)(buf + string_section->SHfileoff);
274 for (unsigned offset = 0; offset < section->SHsecsz; offset += sizeof(elf_symtab))
275 { elf_symtab *sym = (elf_symtab *)(buf + section->SHfileoff + offset);
277 if ((sym->STinfo >> 4) == ST_BIND_GLOBAL &&
278 sym->STdefsht != SHT_UNDEF) // not extern
280 char *name = string_tab + sym->STname;
281 //printf("sym STname = x%x\n", sym->STname);
282 addSymbol(om, name, 1);
289 /***************************************
290 * Add object module or library to the library.
291 * Examine the buffer to see which it is.
292 * If the buffer is NULL, use module_name as the file name
293 * and load the file.
296 void Library::addObject(char *module_name, void *buf, size_t buflen)
298 if (!module_name)
299 module_name = "";
300 #if LOG
301 printf("Library::addObject(%s)\n", module_name);
302 #endif
303 int fromfile = 0;
304 if (!buf)
305 { assert(module_name[0]);
306 FileName f(module_name, 0);
307 File file(&f);
308 file.readv();
309 buf = file.buffer;
310 buflen = file.len;
311 file.ref = 1;
312 fromfile = 1;
314 int reason = 0;
316 if (buflen < 16)
318 Lcorrupt:
319 error("corrupt object module %s %d", module_name, reason);
320 return;
323 if (memcmp(buf, "!<arch>\n", 8) == 0)
324 { /* Library file.
325 * Pull each object module out of the library and add it
326 * to the object module array.
328 unsigned offset = 8;
329 char *symtab = NULL;
330 unsigned symtab_size = 0;
331 char *filenametab = NULL;
332 unsigned filenametab_size = 0;
333 unsigned mstart = objmodules.dim;
334 while (offset < buflen)
336 if (offset + sizeof(Header) >= buflen)
337 { reason = 1;
338 goto Lcorrupt;
340 Header *header = (Header *)((unsigned char *)buf + offset);
341 offset += sizeof(Header);
342 char *endptr = NULL;
343 unsigned long size = strtoul(header->file_size, &endptr, 10);
344 if (endptr >= &header->file_size[10] || *endptr != ' ')
345 goto Lcorrupt;
346 if (offset + size > buflen)
347 goto Lcorrupt;
349 if (header->object_name[0] == '/' &&
350 header->object_name[1] == ' ')
352 /* Instead of rescanning the object modules we pull from a
353 * library, just use the already created symbol table.
355 if (symtab)
356 goto Lcorrupt;
357 symtab = (char *)buf + offset;
358 symtab_size = size;
359 if (size < 4)
360 goto Lcorrupt;
362 else if (header->object_name[0] == '/' &&
363 header->object_name[1] == '/')
365 /* This is the file name table, save it for later.
367 if (filenametab)
368 goto Lcorrupt;
369 filenametab = (char *)buf + offset;
370 filenametab_size = size;
372 else
374 ObjModule *om = new ObjModule();
375 om->base = (unsigned char *)buf + offset - sizeof(Header);
376 om->length = size;
377 om->offset = 0;
378 if (header->object_name[0] == '/')
379 { /* Pick long name out of file name table
381 unsigned foff = strtoul(header->object_name + 1, &endptr, 10);
382 unsigned i;
383 for (i = 0; 1; i++)
384 { if (foff + i >= filenametab_size)
385 goto Lcorrupt;
386 char c = filenametab[foff + i];
387 if (c == '/')
388 break;
390 om->name = (char *)malloc(i + 1);
391 assert(om->name);
392 memcpy(om->name, filenametab + foff, i);
393 om->name[i] = 0;
395 else
396 { /* Pick short name out of header
398 om->name = (char *)malloc(OBJECT_NAME_SIZE);
399 assert(om->name);
400 for (int i = 0; 1; i++)
401 { if (i == OBJECT_NAME_SIZE)
402 goto Lcorrupt;
403 char c = header->object_name[i];
404 if (c == '/')
405 { om->name[i] = 0;
406 break;
408 om->name[i] = c;
411 om->name_offset = -1;
412 om->file_time = strtoul(header->file_time, &endptr, 10);
413 om->user_id = strtoul(header->user_id, &endptr, 10);
414 om->group_id = strtoul(header->group_id, &endptr, 10);
415 om->file_mode = strtoul(header->file_mode, &endptr, 8);
416 om->scan = 0;
417 objmodules.push(om);
419 offset += (size + 1) & ~1;
421 if (offset != buflen)
422 goto Lcorrupt;
424 /* Scan the library's symbol table, and insert it into our own.
425 * We use this instead of rescanning the object module, because
426 * the library's creator may have a different idea of what symbols
427 * go into the symbol table than we do.
428 * This is also probably faster.
430 unsigned nsymbols = sgetl(symtab);
431 char *s = symtab + 4 + nsymbols * 4;
432 if (4 + nsymbols * (4 + 1) > symtab_size)
433 goto Lcorrupt;
434 for (unsigned i = 0; i < nsymbols; i++)
435 { char *name = s;
436 s += strlen(name) + 1;
437 if (s - symtab > symtab_size)
438 goto Lcorrupt;
439 unsigned moff = sgetl(symtab + 4 + i * 4);
440 for (unsigned m = mstart; 1; m++)
441 { if (m == objmodules.dim)
442 goto Lcorrupt; // didn't find it
443 ObjModule *om = (ObjModule *)objmodules.data[m];
444 if (moff + sizeof(Header) == (char *)om->base - (char *)buf)
446 addSymbol(om, name, 1);
447 if (mstart == m)
448 mstart++;
449 break;
454 return;
457 if (memcmp(buf, elf, 4) != 0)
458 { reason = 2;
459 goto Lcorrupt;
462 /* It's an ELF object module
464 ObjModule *om = new ObjModule();
465 om->base = (unsigned char *)buf;
466 om->length = buflen;
467 om->offset = 0;
468 om->name = FileName::name(module_name); // remove path, but not extension
469 om->name_offset = -1;
470 om->scan = 1;
471 if (fromfile)
472 { struct stat statbuf;
473 int i = stat(module_name, &statbuf);
474 if (i == -1) // error, errno is set
475 { reason = 3;
476 goto Lcorrupt;
478 om->file_time = statbuf.st_ctime;
479 om->user_id = statbuf.st_uid;
480 om->group_id = statbuf.st_gid;
481 om->file_mode = statbuf.st_mode;
483 else
484 { /* Mock things up for the object module file that never was
485 * actually written out.
487 static uid_t uid;
488 static gid_t gid;
489 static int init;
490 if (!init)
491 { init = 1;
492 uid = getuid();
493 gid = getgid();
495 time(&om->file_time);
496 om->user_id = uid;
497 om->group_id = gid;
498 om->file_mode = 0100640;
500 objmodules.push(om);
504 /*****************************************************************************/
505 /*****************************************************************************/
507 /**********************************************
508 * Create and write library to libbuf.
509 * The library consists of:
510 * !<arch>\n
511 * header
512 * dictionary
513 * object modules...
516 void Library::WriteLibToBuffer(OutBuffer *libbuf)
518 #if LOG
519 printf("Library::WriteLibToBuffer()\n");
520 #endif
522 /************* Scan Object Modules for Symbols ******************/
524 for (int i = 0; i < objmodules.dim; i++)
525 { ObjModule *om = (ObjModule *)objmodules.data[i];
526 if (om->scan)
528 scanObjModule(om);
532 /************* Determine string section ******************/
534 /* The string section is where we store long file names.
536 unsigned noffset = 0;
537 for (int i = 0; i < objmodules.dim; i++)
538 { ObjModule *om = (ObjModule *)objmodules.data[i];
539 size_t len = strlen(om->name);
540 if (len >= OBJECT_NAME_SIZE)
542 om->name_offset = noffset;
543 noffset += len + 2;
545 else
546 om->name_offset = -1;
549 #if LOG
550 printf("\tnoffset = x%x\n", noffset);
551 #endif
553 /************* Determine module offsets ******************/
555 unsigned moffset = 8 + sizeof(Header) + 4;
557 for (int i = 0; i < objsymbols.dim; i++)
558 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
560 moffset += 4 + strlen(os->name) + 1;
562 unsigned hoffset = moffset;
564 #if LOG
565 printf("\tmoffset = x%x\n", moffset);
566 #endif
568 moffset += moffset & 1;
569 if (noffset)
570 moffset += sizeof(Header) + noffset;
572 for (int i = 0; i < objmodules.dim; i++)
573 { ObjModule *om = (ObjModule *)objmodules.data[i];
575 moffset += moffset & 1;
576 om->offset = moffset;
577 moffset += sizeof(Header) + om->length;
580 libbuf->reserve(moffset);
582 /************* Write the library ******************/
583 libbuf->write("!<arch>\n", 8);
585 ObjModule om;
586 om.name_offset = -1;
587 om.base = NULL;
588 om.length = hoffset - (8 + sizeof(Header));
589 om.offset = 8;
590 om.name = "";
591 ::time(&om.file_time);
592 om.user_id = 0;
593 om.group_id = 0;
594 om.file_mode = 0;
596 Header h;
597 OmToHeader(&h, &om);
598 libbuf->write(&h, sizeof(h));
599 char buf[4];
600 sputl(objsymbols.dim, buf);
601 libbuf->write(buf, 4);
603 for (int i = 0; i < objsymbols.dim; i++)
604 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
606 sputl(os->om->offset, buf);
607 libbuf->write(buf, 4);
610 for (int i = 0; i < objsymbols.dim; i++)
611 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
613 libbuf->writestring(os->name);
614 libbuf->writeByte(0);
617 #if LOG
618 printf("\tlibbuf->moffset = x%x\n", libbuf->offset);
619 #endif
621 /* Write out the string section
623 if (noffset)
625 if (libbuf->offset & 1)
626 libbuf->writeByte('\n');
628 // header
629 memset(&h, ' ', sizeof(Header));
630 h.object_name[0] = '/';
631 h.object_name[1] = '/';
632 size_t len = sprintf(h.file_size, "%u", noffset);
633 assert(len < 10);
634 h.file_size[len] = ' ';
635 h.trailer[0] = '`';
636 h.trailer[1] = '\n';
637 libbuf->write(&h, sizeof(h));
639 for (int i = 0; i < objmodules.dim; i++)
640 { ObjModule *om = (ObjModule *)objmodules.data[i];
641 if (om->name_offset >= 0)
642 { libbuf->writestring(om->name);
643 libbuf->writeByte('/');
644 libbuf->writeByte('\n');
649 /* Write out each of the object modules
651 for (int i = 0; i < objmodules.dim; i++)
652 { ObjModule *om = (ObjModule *)objmodules.data[i];
654 if (libbuf->offset & 1)
655 libbuf->writeByte('\n'); // module alignment
657 assert(libbuf->offset == om->offset);
659 OmToHeader(&h, om);
660 libbuf->write(&h, sizeof(h)); // module header
662 libbuf->write(om->base, om->length); // module contents
665 #if LOG
666 printf("moffset = x%x, libbuf->offset = x%x\n", moffset, libbuf->offset);
667 #endif
668 assert(libbuf->offset == moffset);