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
->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
297 void Library::addObject(char *module_name
, void *buf
, size_t buflen
)
302 printf("Library::addObject(%s)\n", module_name
);
306 { assert(module_name
[0]);
307 FileName
f(module_name
, 0);
320 error("corrupt object module %s %d", module_name
, reason
);
324 if (memcmp(buf
, "!<arch>\n", 8) == 0)
326 * Pull each object module out of the library and add it
327 * to the object module array.
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
)
341 Header
*header
= (Header
*)((unsigned char *)buf
+ offset
);
342 offset
+= sizeof(Header
);
344 unsigned long size
= strtoul(header
->file_size
, &endptr
, 10);
345 if (endptr
>= &header
->file_size
[10] || *endptr
!= ' ')
347 if (offset
+ size
> buflen
)
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.
358 symtab
= (char *)buf
+ offset
;
363 else if (header
->object_name
[0] == '/' &&
364 header
->object_name
[1] == '/')
366 /* This is the file name table, save it for later.
370 filenametab
= (char *)buf
+ offset
;
371 filenametab_size
= size
;
375 ObjModule
*om
= new ObjModule();
376 om
->base
= (unsigned char *)buf
+ offset
- sizeof(Header
);
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);
385 { if (foff
+ i
>= filenametab_size
)
387 char c
= filenametab
[foff
+ i
];
391 om
->name
= (char *)malloc(i
+ 1);
393 memcpy(om
->name
, filenametab
+ foff
, i
);
397 { /* Pick short name out of header
399 om
->name
= (char *)malloc(OBJECT_NAME_SIZE
);
401 for (int i
= 0; 1; i
++)
402 { if (i
== OBJECT_NAME_SIZE
)
404 char c
= header
->object_name
[i
];
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);
420 offset
+= (size
+ 1) & ~1;
422 if (offset
!= buflen
)
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
)
435 for (unsigned i
= 0; i
< nsymbols
; i
++)
437 s
+= strlen(name
) + 1;
438 if (s
- symtab
> symtab_size
)
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);
458 if (memcmp(buf
, elf
, 4) != 0)
463 /* It's an ELF object module
465 ObjModule
*om
= new ObjModule();
466 om
->base
= (unsigned char *)buf
;
469 om
->name
= FileName::name(module_name
); // remove path, but not extension
470 om
->name_offset
= -1;
473 { struct stat statbuf
;
474 int i
= stat(module_name
, &statbuf
);
475 if (i
== -1) // error, errno is set
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
;
485 { /* Mock things up for the object module file that never was
486 * actually written out.
496 time(&om
->file_time
);
499 om
->file_mode
= 0100640;
505 /*****************************************************************************/
506 /*****************************************************************************/
508 /**********************************************
509 * Create and write library to libbuf.
510 * The library consists of:
517 void Library::WriteLibToBuffer(OutBuffer
*libbuf
)
520 printf("Library::WriteLibToBuffer()\n");
523 /************* Scan Object Modules for Symbols ******************/
525 for (int i
= 0; i
< objmodules
.dim
; i
++)
526 { ObjModule
*om
= (ObjModule
*)objmodules
.data
[i
];
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
;
547 om
->name_offset
= -1;
551 printf("\tnoffset = x%x\n", noffset
);
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
;
566 printf("\tmoffset = x%x\n", moffset
);
569 moffset
+= moffset
& 1;
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);
589 om
.length
= hoffset
- (8 + sizeof(Header
));
592 ::time(&om
.file_time
);
599 libbuf
->write(&h
, sizeof(h
));
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);
619 printf("\tlibbuf->moffset = x%x\n", libbuf
->offset
);
622 /* Write out the string section
626 if (libbuf
->offset
& 1)
627 libbuf
->writeByte('\n');
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
);
635 h
.file_size
[len
] = ' ';
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
);
661 libbuf
->write(&h
, sizeof(h
)); // module header
663 libbuf
->write(om
->base
, om
->length
); // module contents
667 printf("moffset = x%x, libbuf->offset = x%x\n", moffset
, libbuf
->offset
);
669 assert(libbuf
->offset
== moffset
);