2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
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.
16 #include <sys/types.h>
21 #include "stringtable.h"
34 /***********************************
35 * Set the library file name based on the output directory
37 * Add default library file name extension.
40 void Library::setFilename(char *dir
, char *filename
)
43 printf("Library::setFilename(dir = '%s', filename = '%s')\n",
44 dir
? dir
: "", filename
? filename
: "");
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
);
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
);
64 if (global
.params
.verbose
)
65 printf("library %s\n", libfile
->name
->toChars());
68 WriteLibToBuffer(&libbuf
);
70 // Transfer image to file
71 libfile
->setbuffer(libbuf
.data
, libbuf
.offset
);
75 char *p
= FileName::path(libfile
->name
->toChars());
76 FileName::ensurePathExists(p
);
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];
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
122 int scan
; // 1 means scan for symbols
127 #define OBJECT_NAME_SIZE 16
128 char object_name
[OBJECT_NAME_SIZE
];
132 char file_mode
[8]; // in octal
137 void OmToHeader(Header
*h
, ObjModule
*om
)
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));
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
);
162 memset(h
->file_time
+ len
, ' ', 12 - len
);
164 len
= sprintf(h
->user_id
, "%u", om
->user_id
);
166 memset(h
->user_id
+ len
, ' ', 6 - len
);
168 len
= sprintf(h
->group_id
, "%u", om
->group_id
);
170 memset(h
->group_id
+ len
, ' ', 6 - len
);
172 len
= sprintf(h
->file_mode
, "%o", om
->file_mode
);
174 memset(h
->file_mode
+ len
, ' ', 8 - len
);
176 len
= sprintf(h
->file_size
, "%u", om
->length
);
178 memset(h
->file_size
+ len
, ' ', 10 - len
);
181 h
->trailer
[1] = '\n';
184 void Library::addSymbol(ObjModule
*om
, char *name
, int pickAny
)
187 printf("Library::addSymbol(%s, %s, %d)\n", om
->name
, name
, pickAny
);
189 StringValue
*s
= tab
.insert(name
, strlen(name
));
191 { // already in table
193 { s
= tab
.lookup(name
, strlen(name
));
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
);
202 ObjSymbol
*os
= new ObjSymbol();
203 os
->name
= strdup(name
);
205 s
->ptrvalue
= (void *)os
;
211 /************************************
212 * Scan single object module for dictionary symbols.
213 * Send those symbols to Library::addSymbol().
216 void Library::scanObjModule(ObjModule
*om
)
219 printf("Library::scanObjModule(%s)\n", om
->name
);
221 unsigned char *buf
= (unsigned char *)om
->base
;
222 size_t buflen
= om
->length
;
225 if (buflen
< sizeof(elf_header_f32
))
228 error("corrupt ELF object module %s %d", om
->name
, reason
);
232 elf_header_f32
*eh
= (elf_header_f32
*)buf
;
233 if (memcmp(buf
, elf
, 4))
237 if (eh
->EHtype
!= EH_TYPE_RELFILE
)
238 return; // not relocatable object module
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);
252 printf("strtab SHfileoff = x%x\n", string_section
->SHfileoff
);
253 char *string_tab
= (char *)(buf
+ string_section
->SHfileoff
);
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
)
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
296 void Library::addObject(char *module_name
, void *buf
, size_t buflen
)
301 printf("Library::addObject(%s)\n", module_name
);
305 { assert(module_name
[0]);
306 FileName
f(module_name
, 0);
319 error("corrupt object module %s %d", module_name
, reason
);
323 if (memcmp(buf
, "!<arch>\n", 8) == 0)
325 * Pull each object module out of the library and add it
326 * to the object module array.
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
)
340 Header
*header
= (Header
*)((unsigned char *)buf
+ offset
);
341 offset
+= sizeof(Header
);
343 unsigned long size
= strtoul(header
->file_size
, &endptr
, 10);
344 if (endptr
>= &header
->file_size
[10] || *endptr
!= ' ')
346 if (offset
+ size
> buflen
)
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.
357 symtab
= (char *)buf
+ offset
;
362 else if (header
->object_name
[0] == '/' &&
363 header
->object_name
[1] == '/')
365 /* This is the file name table, save it for later.
369 filenametab
= (char *)buf
+ offset
;
370 filenametab_size
= size
;
374 ObjModule
*om
= new ObjModule();
375 om
->base
= (unsigned char *)buf
+ offset
- sizeof(Header
);
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);
384 { if (foff
+ i
>= filenametab_size
)
386 char c
= filenametab
[foff
+ i
];
390 om
->name
= (char *)malloc(i
+ 1);
392 memcpy(om
->name
, filenametab
+ foff
, i
);
396 { /* Pick short name out of header
398 om
->name
= (char *)malloc(OBJECT_NAME_SIZE
);
400 for (int i
= 0; 1; i
++)
401 { if (i
== OBJECT_NAME_SIZE
)
403 char c
= header
->object_name
[i
];
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);
419 offset
+= (size
+ 1) & ~1;
421 if (offset
!= buflen
)
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
)
434 for (unsigned i
= 0; i
< nsymbols
; i
++)
436 s
+= strlen(name
) + 1;
437 if (s
- symtab
> symtab_size
)
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);
457 if (memcmp(buf
, elf
, 4) != 0)
462 /* It's an ELF object module
464 ObjModule
*om
= new ObjModule();
465 om
->base
= (unsigned char *)buf
;
468 om
->name
= FileName::name(module_name
); // remove path, but not extension
469 om
->name_offset
= -1;
472 { struct stat statbuf
;
473 int i
= stat(module_name
, &statbuf
);
474 if (i
== -1) // error, errno is set
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
;
484 { /* Mock things up for the object module file that never was
485 * actually written out.
495 time(&om
->file_time
);
498 om
->file_mode
= 0100640;
504 /*****************************************************************************/
505 /*****************************************************************************/
507 /**********************************************
508 * Create and write library to libbuf.
509 * The library consists of:
516 void Library::WriteLibToBuffer(OutBuffer
*libbuf
)
519 printf("Library::WriteLibToBuffer()\n");
522 /************* Scan Object Modules for Symbols ******************/
524 for (int i
= 0; i
< objmodules
.dim
; i
++)
525 { ObjModule
*om
= (ObjModule
*)objmodules
.data
[i
];
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
;
546 om
->name_offset
= -1;
550 printf("\tnoffset = x%x\n", noffset
);
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
;
565 printf("\tmoffset = x%x\n", moffset
);
568 moffset
+= moffset
& 1;
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);
588 om
.length
= hoffset
- (8 + sizeof(Header
));
591 ::time(&om
.file_time
);
598 libbuf
->write(&h
, sizeof(h
));
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);
618 printf("\tlibbuf->moffset = x%x\n", libbuf
->offset
);
621 /* Write out the string section
625 if (libbuf
->offset
& 1)
626 libbuf
->writeByte('\n');
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
);
634 h
.file_size
[len
] = ' ';
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
);
660 libbuf
->write(&h
, sizeof(h
)); // module header
662 libbuf
->write(om
->base
, om
->length
); // module contents
666 printf("moffset = x%x, libbuf->offset = x%x\n", moffset
, libbuf
->offset
);
668 assert(libbuf
->offset
== moffset
);