Warn about "assert X,Y"
[delight/core.git] / dmd2 / libelf.c
blobc2026a8b2f69a49149d837304e2edde308a4ee1d
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 0
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->STinfo >> 4) == ST_BIND_WEAK) &&
279 sym->STdefsht != SHT_UNDEF) // not extern
281 char *name = string_tab + sym->STname;
282 //printf("sym STname = x%x\n", sym->STname);
283 addSymbol(om, name, 1);
290 /***************************************
291 * Add object module or library to the library.
292 * Examine the buffer to see which it is.
293 * If the buffer is NULL, use module_name as the file name
294 * and load the file.
297 void Library::addObject(char *module_name, void *buf, size_t buflen)
299 if (!module_name)
300 module_name = "";
301 #if LOG
302 printf("Library::addObject(%s)\n", module_name);
303 #endif
304 int fromfile = 0;
305 if (!buf)
306 { assert(module_name[0]);
307 FileName f(module_name, 0);
308 File file(&f);
309 file.readv();
310 buf = file.buffer;
311 buflen = file.len;
312 file.ref = 1;
313 fromfile = 1;
315 int reason = 0;
317 if (buflen < 16)
319 Lcorrupt:
320 error("corrupt object module %s %d", module_name, reason);
321 return;
324 if (memcmp(buf, "!<arch>\n", 8) == 0)
325 { /* Library file.
326 * Pull each object module out of the library and add it
327 * to the object module array.
329 unsigned offset = 8;
330 char *symtab = NULL;
331 unsigned symtab_size = 0;
332 char *filenametab = NULL;
333 unsigned filenametab_size = 0;
334 unsigned mstart = objmodules.dim;
335 while (offset < buflen)
337 if (offset + sizeof(Header) >= buflen)
338 { reason = 1;
339 goto Lcorrupt;
341 Header *header = (Header *)((unsigned char *)buf + offset);
342 offset += sizeof(Header);
343 char *endptr = NULL;
344 unsigned long size = strtoul(header->file_size, &endptr, 10);
345 if (endptr >= &header->file_size[10] || *endptr != ' ')
346 goto Lcorrupt;
347 if (offset + size > buflen)
348 goto Lcorrupt;
350 if (header->object_name[0] == '/' &&
351 header->object_name[1] == ' ')
353 /* Instead of rescanning the object modules we pull from a
354 * library, just use the already created symbol table.
356 if (symtab)
357 goto Lcorrupt;
358 symtab = (char *)buf + offset;
359 symtab_size = size;
360 if (size < 4)
361 goto Lcorrupt;
363 else if (header->object_name[0] == '/' &&
364 header->object_name[1] == '/')
366 /* This is the file name table, save it for later.
368 if (filenametab)
369 goto Lcorrupt;
370 filenametab = (char *)buf + offset;
371 filenametab_size = size;
373 else
375 ObjModule *om = new ObjModule();
376 om->base = (unsigned char *)buf + offset - sizeof(Header);
377 om->length = size;
378 om->offset = 0;
379 if (header->object_name[0] == '/')
380 { /* Pick long name out of file name table
382 unsigned foff = strtoul(header->object_name + 1, &endptr, 10);
383 unsigned i;
384 for (i = 0; 1; i++)
385 { if (foff + i >= filenametab_size)
386 goto Lcorrupt;
387 char c = filenametab[foff + i];
388 if (c == '/')
389 break;
391 om->name = (char *)malloc(i + 1);
392 assert(om->name);
393 memcpy(om->name, filenametab + foff, i);
394 om->name[i] = 0;
396 else
397 { /* Pick short name out of header
399 om->name = (char *)malloc(OBJECT_NAME_SIZE);
400 assert(om->name);
401 for (int i = 0; 1; i++)
402 { if (i == OBJECT_NAME_SIZE)
403 goto Lcorrupt;
404 char c = header->object_name[i];
405 if (c == '/')
406 { om->name[i] = 0;
407 break;
409 om->name[i] = c;
412 om->name_offset = -1;
413 om->file_time = strtoul(header->file_time, &endptr, 10);
414 om->user_id = strtoul(header->user_id, &endptr, 10);
415 om->group_id = strtoul(header->group_id, &endptr, 10);
416 om->file_mode = strtoul(header->file_mode, &endptr, 8);
417 om->scan = 0;
418 objmodules.push(om);
420 offset += (size + 1) & ~1;
422 if (offset != buflen)
423 goto Lcorrupt;
425 /* Scan the library's symbol table, and insert it into our own.
426 * We use this instead of rescanning the object module, because
427 * the library's creator may have a different idea of what symbols
428 * go into the symbol table than we do.
429 * This is also probably faster.
431 unsigned nsymbols = sgetl(symtab);
432 char *s = symtab + 4 + nsymbols * 4;
433 if (4 + nsymbols * (4 + 1) > symtab_size)
434 goto Lcorrupt;
435 for (unsigned i = 0; i < nsymbols; i++)
436 { char *name = s;
437 s += strlen(name) + 1;
438 if (s - symtab > symtab_size)
439 goto Lcorrupt;
440 unsigned moff = sgetl(symtab + 4 + i * 4);
441 for (unsigned m = mstart; 1; m++)
442 { if (m == objmodules.dim)
443 goto Lcorrupt; // didn't find it
444 ObjModule *om = (ObjModule *)objmodules.data[m];
445 if (moff + sizeof(Header) == (char *)om->base - (char *)buf)
447 addSymbol(om, name, 1);
448 if (mstart == m)
449 mstart++;
450 break;
455 return;
458 if (memcmp(buf, elf, 4) != 0)
459 { reason = 2;
460 goto Lcorrupt;
463 /* It's an ELF object module
465 ObjModule *om = new ObjModule();
466 om->base = (unsigned char *)buf;
467 om->length = buflen;
468 om->offset = 0;
469 om->name = FileName::name(module_name); // remove path, but not extension
470 om->name_offset = -1;
471 om->scan = 1;
472 if (fromfile)
473 { struct stat statbuf;
474 int i = stat(module_name, &statbuf);
475 if (i == -1) // error, errno is set
476 { reason = 3;
477 goto Lcorrupt;
479 om->file_time = statbuf.st_ctime;
480 om->user_id = statbuf.st_uid;
481 om->group_id = statbuf.st_gid;
482 om->file_mode = statbuf.st_mode;
484 else
485 { /* Mock things up for the object module file that never was
486 * actually written out.
488 static uid_t uid;
489 static gid_t gid;
490 static int init;
491 if (!init)
492 { init = 1;
493 uid = getuid();
494 gid = getgid();
496 time(&om->file_time);
497 om->user_id = uid;
498 om->group_id = gid;
499 om->file_mode = 0100640;
501 objmodules.push(om);
505 /*****************************************************************************/
506 /*****************************************************************************/
508 /**********************************************
509 * Create and write library to libbuf.
510 * The library consists of:
511 * !<arch>\n
512 * header
513 * dictionary
514 * object modules...
517 void Library::WriteLibToBuffer(OutBuffer *libbuf)
519 #if LOG
520 printf("Library::WriteLibToBuffer()\n");
521 #endif
523 /************* Scan Object Modules for Symbols ******************/
525 for (int i = 0; i < objmodules.dim; i++)
526 { ObjModule *om = (ObjModule *)objmodules.data[i];
527 if (om->scan)
529 scanObjModule(om);
533 /************* Determine string section ******************/
535 /* The string section is where we store long file names.
537 unsigned noffset = 0;
538 for (int i = 0; i < objmodules.dim; i++)
539 { ObjModule *om = (ObjModule *)objmodules.data[i];
540 size_t len = strlen(om->name);
541 if (len >= OBJECT_NAME_SIZE)
543 om->name_offset = noffset;
544 noffset += len + 2;
546 else
547 om->name_offset = -1;
550 #if LOG
551 printf("\tnoffset = x%x\n", noffset);
552 #endif
554 /************* Determine module offsets ******************/
556 unsigned moffset = 8 + sizeof(Header) + 4;
558 for (int i = 0; i < objsymbols.dim; i++)
559 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
561 moffset += 4 + strlen(os->name) + 1;
563 unsigned hoffset = moffset;
565 #if LOG
566 printf("\tmoffset = x%x\n", moffset);
567 #endif
569 moffset += moffset & 1;
570 if (noffset)
571 moffset += sizeof(Header) + noffset;
573 for (int i = 0; i < objmodules.dim; i++)
574 { ObjModule *om = (ObjModule *)objmodules.data[i];
576 moffset += moffset & 1;
577 om->offset = moffset;
578 moffset += sizeof(Header) + om->length;
581 libbuf->reserve(moffset);
583 /************* Write the library ******************/
584 libbuf->write("!<arch>\n", 8);
586 ObjModule om;
587 om.name_offset = -1;
588 om.base = NULL;
589 om.length = hoffset - (8 + sizeof(Header));
590 om.offset = 8;
591 om.name = "";
592 ::time(&om.file_time);
593 om.user_id = 0;
594 om.group_id = 0;
595 om.file_mode = 0;
597 Header h;
598 OmToHeader(&h, &om);
599 libbuf->write(&h, sizeof(h));
600 char buf[4];
601 sputl(objsymbols.dim, buf);
602 libbuf->write(buf, 4);
604 for (int i = 0; i < objsymbols.dim; i++)
605 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
607 sputl(os->om->offset, buf);
608 libbuf->write(buf, 4);
611 for (int i = 0; i < objsymbols.dim; i++)
612 { ObjSymbol *os = (ObjSymbol *)objsymbols.data[i];
614 libbuf->writestring(os->name);
615 libbuf->writeByte(0);
618 #if LOG
619 printf("\tlibbuf->moffset = x%x\n", libbuf->offset);
620 #endif
622 /* Write out the string section
624 if (noffset)
626 if (libbuf->offset & 1)
627 libbuf->writeByte('\n');
629 // header
630 memset(&h, ' ', sizeof(Header));
631 h.object_name[0] = '/';
632 h.object_name[1] = '/';
633 size_t len = sprintf(h.file_size, "%u", noffset);
634 assert(len < 10);
635 h.file_size[len] = ' ';
636 h.trailer[0] = '`';
637 h.trailer[1] = '\n';
638 libbuf->write(&h, sizeof(h));
640 for (int i = 0; i < objmodules.dim; i++)
641 { ObjModule *om = (ObjModule *)objmodules.data[i];
642 if (om->name_offset >= 0)
643 { libbuf->writestring(om->name);
644 libbuf->writeByte('/');
645 libbuf->writeByte('\n');
650 /* Write out each of the object modules
652 for (int i = 0; i < objmodules.dim; i++)
653 { ObjModule *om = (ObjModule *)objmodules.data[i];
655 if (libbuf->offset & 1)
656 libbuf->writeByte('\n'); // module alignment
658 assert(libbuf->offset == om->offset);
660 OmToHeader(&h, om);
661 libbuf->write(&h, sizeof(h)); // module header
663 libbuf->write(om->base, om->length); // module contents
666 #if LOG
667 printf("moffset = x%x, libbuf->offset = x%x\n", moffset, libbuf->offset);
668 #endif
669 assert(libbuf->offset == moffset);