tcc -vv ... : show objects loaded from archives

This commit is contained in:
grischka 2019-12-10 20:50:45 +01:00
parent df349ddc43
commit 6082dd62bb

122
tccelf.c
View File

@ -2795,59 +2795,78 @@ typedef struct ArchiveHeader {
char ar_fmag[2]; /* should contain ARFMAG */ char ar_fmag[2]; /* should contain ARFMAG */
} ArchiveHeader; } ArchiveHeader;
static int get_be32(const uint8_t *b) #define ARFMAG "`\n"
static unsigned long long get_be(const uint8_t *b, int n)
{ {
return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); unsigned long long ret = 0;
while (n)
ret = (ret << 8) | *b++, --n;
return ret;
} }
static long get_be64(const uint8_t *b) static int read_ar_header(int fd, int offset, ArchiveHeader *hdr)
{ {
long long ret = get_be32(b); char *p, *e;
ret = (ret << 32) | (unsigned)get_be32(b+4); int len;
return (long)ret; lseek(fd, offset, SEEK_SET);
len = full_read(fd, hdr, sizeof(ArchiveHeader));
if (len != sizeof(ArchiveHeader))
return len ? -1 : 0;
p = hdr->ar_name;
for (e = p + sizeof hdr->ar_name; e > p && e[-1] == ' ';)
--e;
*e = '\0';
hdr->ar_size[sizeof hdr->ar_size-1] = 0;
return len;
} }
/* load only the objects which resolve undefined symbols */ /* load only the objects which resolve undefined symbols */
static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
{ {
long i, bound, nsyms, sym_index, off, ret; int i, bound, nsyms, sym_index, len, ret = -1;
unsigned long long off;
uint8_t *data; uint8_t *data;
const char *ar_names, *p; const char *ar_names, *p;
const uint8_t *ar_index; const uint8_t *ar_index;
ElfW(Sym) *sym; ElfW(Sym) *sym;
Section *s; ArchiveHeader hdr;
data = tcc_malloc(size); data = tcc_malloc(size);
if (full_read(fd, data, size) != size) if (full_read(fd, data, size) != size)
goto fail; goto the_end;
nsyms = entrysize == 4 ? get_be32(data) : get_be64(data); nsyms = get_be(data, entrysize);
ar_index = data + entrysize; ar_index = data + entrysize;
ar_names = (char *) ar_index + nsyms * entrysize; ar_names = (char *) ar_index + nsyms * entrysize;
do { do {
bound = 0; bound = 0;
for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
s = symtab_section; Section *s = symtab_section;
sym_index = find_elf_sym(s, p); sym_index = find_elf_sym(s, p);
if(sym_index == 0) { #ifdef TCC_TARGET_PE /* windows DLL's don't have UNDEF syms */
if (sym_index == 0) {
s = s1->dynsymtab_section; s = s1->dynsymtab_section;
sym_index = find_elf_sym(s, p); sym_index = find_elf_sym(s, p);
} }
if(sym_index) { #endif
sym = &((ElfW(Sym) *)s->data)[sym_index]; if (!sym_index)
if(sym->st_shndx == SHN_UNDEF) { continue;
off = (entrysize == 4 sym = &((ElfW(Sym) *)s->data)[sym_index];
? get_be32(ar_index + i * 4) if(sym->st_shndx != SHN_UNDEF)
: get_be64(ar_index + i * 8)) continue;
+ sizeof(ArchiveHeader); off = get_be(ar_index + i * entrysize, entrysize);
++bound; len = read_ar_header(fd, off, &hdr);
if(tcc_load_object_file(s1, fd, off) < 0) { if (len <= 0 || memcmp(hdr.ar_fmag, ARFMAG, 2)) {
fail: tcc_error_noabort("invalid archive");
ret = -1; goto the_end;
goto the_end;
}
}
} }
off += len;
if (s1->verbose == 2)
printf(" -> %s\n", hdr.ar_name);
if (tcc_load_object_file(s1, fd, off) < 0)
goto the_end;
++bound;
} }
} while(bound); } while(bound);
ret = 0; ret = 0;
@ -2860,52 +2879,41 @@ static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte) ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
{ {
ArchiveHeader hdr; ArchiveHeader hdr;
char ar_size[11]; /* char magic[8]; */
char ar_name[17]; int size, len;
char magic[8];
int size, len, i;
unsigned long file_offset; unsigned long file_offset;
ElfW(Ehdr) ehdr;
/* skip magic which was already checked */ /* skip magic which was already checked */
full_read(fd, magic, sizeof(magic)); /* full_read(fd, magic, sizeof(magic)); */
file_offset = sizeof ARMAG - 1;
for(;;) { for(;;) {
len = full_read(fd, &hdr, sizeof(hdr)); len = read_ar_header(fd, file_offset, &hdr);
if (len == 0) if (len == 0)
break; return 0;
if (len != sizeof(hdr)) { if (len < 0) {
tcc_error_noabort("invalid archive"); tcc_error_noabort("invalid archive");
return -1; return -1;
} }
memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); file_offset += len;
ar_size[sizeof(hdr.ar_size)] = '\0'; size = strtol(hdr.ar_size, NULL, 0);
size = strtol(ar_size, NULL, 0);
memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name));
for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) {
if (ar_name[i] != ' ')
break;
}
ar_name[i + 1] = '\0';
file_offset = lseek(fd, 0, SEEK_CUR);
/* align to even */ /* align to even */
size = (size + 1) & ~1; size = (size + 1) & ~1;
if (!strcmp(ar_name, "/")) { if (alacarte) {
/* coff symbol table : we handle it */ /* coff symbol table : we handle it */
if (alacarte) if (!strcmp(hdr.ar_name, "/"))
return tcc_load_alacarte(s1, fd, size, 4); return tcc_load_alacarte(s1, fd, size, 4);
} else if (!strcmp(ar_name, "/SYM64/")) { if (!strcmp(hdr.ar_name, "/SYM64/"))
if (alacarte)
return tcc_load_alacarte(s1, fd, size, 8); return tcc_load_alacarte(s1, fd, size, 8);
} else { } else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
ElfW(Ehdr) ehdr; if (s1->verbose == 2)
if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { printf(" -> %s\n", hdr.ar_name);
if (tcc_load_object_file(s1, fd, file_offset) < 0) if (tcc_load_object_file(s1, fd, file_offset) < 0)
return -1; return -1;
}
} }
lseek(fd, file_offset + size, SEEK_SET); file_offset += size;
} }
return 0;
} }
#ifndef ELF_OBJ_ONLY #ifndef ELF_OBJ_ONLY