added archive support - better ELF output - fixed symbol relocation - added COMMON symbol handling

This commit is contained in:
bellard 2002-07-18 00:51:11 +00:00
parent f75e0c6d62
commit 7b54a53e08

656
tcc.c
View File

@ -6314,33 +6314,13 @@ static unsigned long elf_hash(const unsigned char *name)
return h;
}
/* add one symbol in hash table if it is global */
/* WARNING: must be called each time a symbol is added otherwise the
hash table is not synchronized with the symbol table */
static void update_hash_elf_sym(Section *hs,
int sym_index, int info, const char *name)
{
int nbuckets, h;
/* only add global symbols */
if (ELF32_ST_BIND(info) == STB_GLOBAL) {
/* add another hashing entry */
nbuckets = ((int *)hs->data)[0];
h = elf_hash(name) % nbuckets;
((int *)hs->data)[2 + nbuckets + sym_index] = ((int *)hs->data)[2 + h];
((int *)hs->data)[2 + h] = sym_index;
}
/* but still add room for all symbols */
((int *)hs->data)[1]++;
hs->data_ptr += sizeof(int);
}
/* return the symbol number */
static int put_elf_sym(Section *s,
unsigned long value, unsigned long size,
int info, int other, int shndx, const char *name)
{
int name_offset, sym_index;
int nbuckets, h;
Elf32_Sym *sym;
Section *hs;
@ -6359,7 +6339,17 @@ static int put_elf_sym(Section *s,
sym_index = sym - (Elf32_Sym *)s->data;
hs = s->hash;
if (hs) {
update_hash_elf_sym(hs, sym_index, info, name);
/* only add global or weak symbols */
if (ELF32_ST_BIND(info) != STB_LOCAL) {
/* add another hashing entry */
nbuckets = ((int *)hs->data)[0];
h = elf_hash(name) % nbuckets;
((int *)hs->data)[2 + nbuckets + sym_index] = ((int *)hs->data)[2 + h];
((int *)hs->data)[2 + h] = sym_index;
}
/* but still add room for all symbols */
((int *)hs->data)[1]++;
hs->data_ptr += sizeof(int);
}
s->data_ptr += sizeof(Elf32_Sym);
return sym_index;
@ -6390,12 +6380,74 @@ static int find_elf_sym(Section *s, const char *name)
return 0;
}
/* return elf symbol value or error */
static unsigned long get_elf_sym_val(const char *name)
{
int sym_index;
Elf32_Sym *sym;
sym_index = find_elf_sym(symtab_section, name);
if (!sym_index)
error("%s not defined", name);
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
return sym->st_value;
}
/* add an elf symbol : check if it is already defined and patch
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
static int add_elf_sym(unsigned long value, unsigned long size,
int info, int sh_num, const char *name)
{
Elf32_Sym *esym;
int sym_bind, sym_index, sym_type, esym_bind;
sym_bind = ELF32_ST_BIND(info);
sym_type = ELF32_ST_TYPE(info);
if (sym_bind != STB_LOCAL) {
/* we search global or weak symbols */
sym_index = find_elf_sym(symtab_section, name);
if (!sym_index)
goto do_def;
esym = &((Elf32_Sym *)symtab_section->data)[sym_index];
if (esym->st_shndx != SHN_UNDEF) {
esym_bind = ELF32_ST_BIND(esym->st_info);
if (sh_num == SHN_UNDEF) {
/* ignore adding of undefined symbol if the
corresponding symbol is already defined */
} else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {
/* global overrides weak, so patch */
goto do_patch;
} else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
/* weak is ignored if already global */
} else {
#if 0
printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n",
sym_bind, sh_num, esym_bind, esym->st_shndx);
#endif
error("'%s' defined twice", name);
}
} else {
do_patch:
esym->st_info = ELF32_ST_INFO(sym_bind, sym_type);
esym->st_shndx = sh_num;
esym->st_value = value;
esym->st_size = size;
}
} else {
do_def:
sym_index = put_elf_sym(symtab_section, value, size,
ELF32_ST_INFO(sym_bind, sym_type), 0,
sh_num, name);
}
return sym_index;
}
/* update sym->c so that it points to an external symbol in section
'section' with value 'value' */
/* XXX: get rid of put_elf_sym */
void put_extern_sym(Sym *sym, Section *section, unsigned long value)
{
int sym_type, sym_bind, sh_num;
int sym_type, sym_bind, sh_num, info;
Elf32_Sym *esym;
const char *name;
@ -6412,27 +6464,9 @@ void put_extern_sym(Sym *sym, Section *section, unsigned long value)
sym_bind = STB_LOCAL;
else
sym_bind = STB_GLOBAL;
/* if the symbol is global, then we look if it is already
defined */
name = get_tok_str(sym->v, NULL);
if (sym_bind == STB_GLOBAL) {
sym->c = find_elf_sym(symtab_section, name);
if (!sym->c)
goto do_def;
/* check if not defined */
if (section) {
esym = &((Elf32_Sym *)symtab_section->data)[sym->c];
if (esym->st_shndx != SHN_UNDEF)
error("'%s' defined twice", name);
esym->st_shndx = sh_num;
esym->st_value = value;
}
} else {
do_def:
sym->c = put_elf_sym(symtab_section, value, 0,
ELF32_ST_INFO(sym_bind, sym_type), 0,
sh_num, name);
}
info = ELF32_ST_INFO(sym_bind, sym_type);
sym->c = add_elf_sym(value, 0, info, sh_num, name);
} else {
esym = &((Elf32_Sym *)symtab_section->data)[sym->c];
esym->st_value = value;
@ -6509,7 +6543,7 @@ static void put_stabd(int type, int other, int desc)
the global and weak ones. Since TCC cannot sort it while generating
the code, we must do it after. All the relocation tables are also
modified to take into account the symbol table sorting */
static void sort_symbols(Section *s)
static void sort_syms(Section *s)
{
int *old_to_new_syms;
Elf32_Sym *new_syms;
@ -6570,16 +6604,78 @@ static void sort_symbols(Section *s)
free(old_to_new_syms);
}
static unsigned long get_sym_val(int sym_index)
/* relocate common symbols in the .bss section */
static void relocate_common_syms(void)
{
unsigned long val;
Elf32_Sym *sym;
unsigned long offset, align;
sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
val = sym->st_value;
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
val += sections[sym->st_shndx]->sh_addr;
return val;
for(sym = (Elf32_Sym *)symtab_section->data + 1;
sym < (Elf32_Sym *)symtab_section->data_ptr;
sym++) {
if (sym->st_shndx == SHN_COMMON) {
/* align symbol */
align = sym->st_value;
offset = bss_section->data_ptr - bss_section->data;
offset = (offset + align - 1) & -align;
sym->st_value = offset;
sym->st_shndx = bss_section->sh_num;
offset += sym->st_size;
bss_section->data_ptr = bss_section->data + offset;
}
}
}
static void *resolve_sym(const char *sym)
{
#ifdef CONFIG_TCC_BCHECK
if (do_bounds_check) {
void *ptr;
ptr = bound_resolve_sym(sym);
if (ptr)
return ptr;
}
#endif
return dlsym(NULL, sym);
}
/* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */
static void relocate_syms(int do_resolve)
{
Elf32_Sym *sym;
int sym_bind, sh_num;
const char *name;
unsigned long addr;
for(sym = (Elf32_Sym *)symtab_section->data + 1;
sym < (Elf32_Sym *)symtab_section->data_ptr;
sym++) {
sh_num = sym->st_shndx;
if (sh_num == SHN_UNDEF) {
name = strtab_section->data + sym->st_name;
if (do_resolve) {
name = symtab_section->link->data + sym->st_name;
addr = (unsigned long)resolve_sym(name);
if (addr) {
sym->st_value = addr;
goto found;
}
}
/* only weak symbols are accepted to be undefined. Their value is zero */
sym_bind = ELF32_ST_BIND(sym->st_info);
if (sym_bind == STB_WEAK) {
sym->st_value = 0;
} else {
// error("undefined symbol '%s'", name);
warning("undefined symbol '%s'", name);
}
} else if (sh_num < SHN_LORESERVE) {
/* add section base */
sym->st_value += sections[sym->st_shndx]->sh_addr;
}
found: ;
}
}
/* relocate a given section */
@ -6587,6 +6683,7 @@ static void relocate_section(Section *s)
{
Section *sr;
Elf32_Rel *rel;
Elf32_Sym *sym;
int type;
unsigned char *ptr;
unsigned long val;
@ -6596,7 +6693,9 @@ static void relocate_section(Section *s)
rel < (Elf32_Rel *)sr->data_ptr;
rel++) {
ptr = s->data + rel->r_offset;
val = get_sym_val(ELF32_R_SYM(rel->r_info));
sym = &((Elf32_Sym *)symtab_section->data)[ELF32_R_SYM(rel->r_info)];
val = sym->st_value;
type = ELF32_R_TYPE(rel->r_info);
greloc_patch(ptr, s->sh_addr + rel->r_offset, val, type);
}
@ -6669,74 +6768,84 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
dynstr = NULL; /* avoid warning */
saved_dynamic_data_ptr = NULL; /* avoid warning */
if (file_type != TCC_FILE_OBJ && !static_link) {
const char *name;
int nb_plt_entries;
if (file_type == TCC_FILE_EXE) {
/* add interpreter section only if executable */
interp = new_section(".interp", SHT_PROGBITS, SHF_ALLOC);
interp->sh_addralign = 1;
strcpy(interp->data_ptr, elf_interp);
interp->data_ptr += sizeof(elf_interp);
}
/* add dynamic symbol table */
dynsym = new_section(".dynsym", SHT_DYNSYM, SHF_ALLOC);
dynsym->sh_entsize = sizeof(Elf32_Sym);
dynstr = new_section(".dynstr", SHT_STRTAB, SHF_ALLOC);
put_elf_str(dynstr, "");
dynsym->link = dynstr;
put_elf_sym(dynsym, 0, 0, 0, 0, 0, NULL);
/* hash table */
hash = new_section_hash(".hash", SHF_ALLOC,
ELF_DYNSYM_HASH_SIZE, dynsym);
if (file_type != TCC_FILE_OBJ) {
/* add dynamic section */
dynamic = new_section(".dynamic", SHT_DYNAMIC,
SHF_ALLOC | SHF_WRITE);
dynamic->link = dynstr;
dynamic->sh_entsize = sizeof(Elf32_Dyn);
/* add PLT and GOT */
plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
plt->sh_entsize = 4;
relocate_common_syms();
/* a got is needed even if static link for the symbol
_GLOBAL_OFFSET_TABLE_ */
got = new_section(".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
got->sh_entsize = 4;
add_elf_sym(0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
got->sh_num, "_GLOBAL_OFFSET_TABLE_");
/* keep space for _DYNAMIC pointer, if present */
got->data_ptr += 4;
if (!static_link) {
const char *name;
int nb_plt_entries;
if (file_type == TCC_FILE_EXE) {
/* add interpreter section only if executable */
interp = new_section(".interp", SHT_PROGBITS, SHF_ALLOC);
interp->sh_addralign = 1;
strcpy(interp->data_ptr, elf_interp);
interp->data_ptr += sizeof(elf_interp);
}
/* add dynamic symbol table */
dynsym = new_section(".dynsym", SHT_DYNSYM, SHF_ALLOC);
dynsym->sh_entsize = sizeof(Elf32_Sym);
dynstr = new_section(".dynstr", SHT_STRTAB, SHF_ALLOC);
put_elf_str(dynstr, "");
dynsym->link = dynstr;
put_elf_sym(dynsym, 0, 0, 0, 0, 0, NULL);
/* hash table */
hash = new_section_hash(".hash", SHF_ALLOC,
ELF_DYNSYM_HASH_SIZE, dynsym);
/* add undefined symbols in dynamic symbol table */
nb_plt_entries = 0;
for(sym = (Elf32_Sym *)symtab_section->data + 1;
sym < (Elf32_Sym *)symtab_section->data_ptr;
sym++) {
if (sym->st_shndx == SHN_UNDEF) {
name = symtab_section->link->data + sym->st_name;
type = ELF32_ST_TYPE(sym->st_info);
put_elf_sym(dynsym, 0, 0,
sym->st_info, 0, SHN_UNDEF, name);
if (type == STT_FUNC) {
nb_plt_entries++;
/* prepare space for relocation */
put_elf_reloc(dynsym, got, 0, 0, 0);
/* add dynamic section */
dynamic = new_section(".dynamic", SHT_DYNAMIC,
SHF_ALLOC | SHF_WRITE);
dynamic->link = dynstr;
dynamic->sh_entsize = sizeof(Elf32_Dyn);
/* add PLT and GOT */
plt = new_section(".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
plt->sh_entsize = 4;
/* add undefined symbols in dynamic symbol table */
nb_plt_entries = 0;
for(sym = (Elf32_Sym *)symtab_section->data + 1;
sym < (Elf32_Sym *)symtab_section->data_ptr;
sym++) {
if (sym->st_shndx == SHN_UNDEF) {
name = symtab_section->link->data + sym->st_name;
type = ELF32_ST_TYPE(sym->st_info);
put_elf_sym(dynsym, 0, 0,
sym->st_info, 0, SHN_UNDEF, name);
if (type == STT_FUNC) {
nb_plt_entries++;
/* prepare space for relocation */
put_elf_reloc(dynsym, got, 0, 0, 0);
}
}
}
}
/* update PLT/GOT sizes so that we can allocate their space */
plt->data_ptr += 16 * (nb_plt_entries + 1);
got->data_ptr += 4 * (nb_plt_entries + 3);
/* update PLT/GOT sizes so that we can allocate their space */
plt->data_ptr += 16 * (nb_plt_entries + 1);
got->data_ptr += 4 * (nb_plt_entries + 2);
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, "libc.so.6"));
/* XXX: add other libs */
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, "libc.so.6"));
/* XXX: add other libs */
/* add necessary space for other entries */
saved_dynamic_data_ptr = dynamic->data_ptr;
dynamic->data_ptr += 8 * 9;
/* add necessary space for other entries */
saved_dynamic_data_ptr = dynamic->data_ptr;
dynamic->data_ptr += 8 * 9;
}
}
sort_symbols(symtab_section);
memset(&ehdr, 0, sizeof(ehdr));
/* we add a section for symbols */
@ -6967,17 +7076,22 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
file_offset += s->sh_size;
}
#if 1
/* if building executable, then relocate each section except the GOT
which is already relocated */
if (file_type == TCC_FILE_EXE) {
/* if building executable or DLL, then relocate each section
except the GOT which is already relocated */
if (file_type != TCC_FILE_OBJ) {
relocate_syms(0);
for(i = 1; i < nb_sections; i++) {
s = sections[i];
if (s->reloc && s != got)
relocate_section(s);
}
/* get entry point address */
ehdr.e_entry = get_elf_sym_val("_start");
}
#endif
sort_syms(symtab_section);
/* align to 4 */
file_offset = (file_offset + 3) & -4;
@ -7004,7 +7118,6 @@ int tcc_output_file(TCCState *s1, const char *filename, int file_type)
}
ehdr.e_machine = EM_386;
ehdr.e_version = EV_CURRENT;
ehdr.e_entry = 0; /* XXX: patch it */
ehdr.e_shoff = file_offset;
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
ehdr.e_shentsize = sizeof(Elf32_Shdr);
@ -7076,22 +7189,21 @@ typedef struct SectionMergeInfo {
/* load an object file and merge it with current files */
/* XXX: handle correctly stab (debug) info */
int tcc_load_object(TCCState *s1, const char *filename)
static int tcc_load_object_file(TCCState *s1,
const char *filename,
FILE *f, unsigned long file_offset)
{
Elf32_Ehdr ehdr;
FILE *f;
Elf32_Shdr *shdr, *sh;
int size, i, j, offset, offsetl, offseti;
unsigned char *strsec;
char *sh_name;
int size, i, j, offset, offseti, nb_syms, sym_index;
unsigned char *strsec, *strtab;
int *old_to_new_syms;
char *sh_name, *name;
SectionMergeInfo *sm_table, *sm;
Elf32_Sym *sym;
Elf32_Sym *sym, *symtab;
Elf32_Rel *rel;
Section *s, *sl;
Section *s;
f = fopen(filename, "r");
if (!f)
error("could not open '%s'", filename);
if (fread(&ehdr, 1, sizeof(ehdr), f) != sizeof(ehdr))
goto fail;
if (ehdr.e_ident[0] != ELFMAG0 ||
@ -7113,7 +7225,7 @@ int tcc_load_object(TCCState *s1, const char *filename)
shdr = malloc(size);
if (!shdr)
error("memory full");
fseek(f, ehdr.e_shoff, SEEK_SET);
fseek(f, file_offset + ehdr.e_shoff, SEEK_SET);
if (fread(shdr, 1, size, f) != size)
goto fail;
@ -7127,9 +7239,36 @@ int tcc_load_object(TCCState *s1, const char *filename)
strsec = malloc(sh->sh_size);
if (!strsec)
error("memory full");
fseek(f, sh->sh_offset, SEEK_SET);
fseek(f, file_offset + sh->sh_offset, SEEK_SET);
fread(strsec, 1, sh->sh_size, f);
/* load symtab and strtab */
symtab = NULL;
strtab = NULL;
nb_syms = 0;
for(i = 1; i < ehdr.e_shnum; i++) {
sh = &shdr[i];
if (sh->sh_type == SHT_SYMTAB) {
if (symtab)
error("object must contain only one symtab");
nb_syms = sh->sh_size / sizeof(Elf32_Sym);
symtab = malloc(sh->sh_size);
if (!symtab)
error("memory full");
fseek(f, file_offset + sh->sh_offset, SEEK_SET);
fread(symtab, 1, sh->sh_size, f);
sm_table[i].s = symtab_section;
/* now load strtab */
sh = &shdr[sh->sh_link];
strtab = malloc(sh->sh_size);
if (!strtab)
error("memory full");
fseek(f, file_offset + sh->sh_offset, SEEK_SET);
fread(strtab, 1, sh->sh_size, f);
}
}
/* now examine each section and try to merge its content with the
ones in memory */
for(i = 1; i < ehdr.e_shnum; i++) {
@ -7138,11 +7277,8 @@ int tcc_load_object(TCCState *s1, const char *filename)
continue;
sh = &shdr[i];
sh_name = strsec + sh->sh_name;
printf("%d: sh_name=%s\n", i, sh_name);
/* ignore sections types we do not handle */
if (sh->sh_type != SHT_PROGBITS &&
sh->sh_type != SHT_SYMTAB &&
sh->sh_type != SHT_STRTAB &&
sh->sh_type != SHT_REL &&
sh->sh_type != SHT_NOBITS)
continue;
@ -7164,11 +7300,6 @@ int tcc_load_object(TCCState *s1, const char *filename)
found:
if (sh->sh_type != s->sh_type)
goto fail;
if (sh->sh_type == SHT_SYMTAB) {
/* if symbol, suppress first dummy entry */
sh->sh_size -= sizeof(Elf32_Sym);
sh->sh_offset += sizeof(Elf32_Sym);
}
/* align start of section */
offset = s->data_ptr - s->data;
@ -7182,7 +7313,7 @@ int tcc_load_object(TCCState *s1, const char *filename)
/* concatenate sections */
size = sh->sh_size;
if (sh->sh_type != SHT_NOBITS) {
fseek(f, sh->sh_offset, SEEK_SET);
fseek(f, file_offset + sh->sh_offset, SEEK_SET);
fread(s->data_ptr, 1, size, f);
}
s->data_ptr += size;
@ -7205,7 +7336,32 @@ int tcc_load_object(TCCState *s1, const char *filename)
}
}
/* third pass to patch symbol and relocation entries */
/* resolve symbols */
old_to_new_syms = malloc(nb_syms * sizeof(int));
if (!old_to_new_syms)
error("memory full");
memset(old_to_new_syms, 0, nb_syms * sizeof(int));
sym = symtab + 1;
for(i = 1; i < nb_syms; i++, sym++) {
if (sym->st_shndx != SHN_UNDEF &&
sym->st_shndx < SHN_LORESERVE) {
sm = &sm_table[sym->st_shndx];
/* if no corresponding section added, no need to add symbol */
if (!sm->s)
continue;
/* convert section number */
sym->st_shndx = sm->s->sh_num;
/* offset value */
sym->st_value += sm->offset;
}
/* add symbol */
name = strtab + sym->st_name;
sym_index = add_elf_sym(sym->st_value, sym->st_size,
sym->st_info, sym->st_shndx, name);
old_to_new_syms[i] = sym_index;
}
/* third pass to patch relocation entries */
for(i = 1; i < ehdr.e_shnum; i++) {
s = sm_table[i].s;
if (!s)
@ -7213,59 +7369,25 @@ int tcc_load_object(TCCState *s1, const char *filename)
sh = &shdr[i];
offset = sm_table[i].offset;
switch(s->sh_type) {
case SHT_SYMTAB:
/* take strtab offset information */
sl = sm_table[sh->sh_link].s;
offsetl = sm_table[sh->sh_link].offset;
for(sym = (Elf32_Sym *)(s->data + offset);
sym < (Elf32_Sym *)s->data_ptr;
sym++) {
/* offset name */
if (sym->st_name != 0)
sym->st_name += offsetl;
/* add to internal hash table */
if (s->hash) {
update_hash_elf_sym(s->hash, sym - (Elf32_Sym *)s->data,
sym->st_info, sl->data + sym->st_name);
}
/* no need to patch */
if (sym->st_shndx == SHN_UNDEF ||
sym->st_shndx >= SHN_LORESERVE)
continue;
/* transform section number */
sm = &sm_table[sym->st_shndx];
if (sm->s) {
sym->st_shndx = sm->s->sh_num;
/* offset value */
sym->st_value += sm->offset;
} else {
/* if the section was suppressed, we put a dummy symbol */
/* XXX: suppress it ? */
sym->st_value = 0;
sym->st_shndx = SHN_ABS;
sym->st_info = 0;
sym->st_name = 0;
printf("warning: invalid symbol %d\n",
sym - (Elf32_Sym *)(s->data + offset) + 1);
}
}
break;
case SHT_REL:
/* take symbol offset information */
/* minus one because we deleted the first symbol */
offsetl = (sm_table[sh->sh_link].offset / sizeof(Elf32_Sym)) - 1;
/* take relocation offset information */
offseti = sm_table[sh->sh_info].offset;
for(rel = (Elf32_Rel *)(s->data + offset);
rel < (Elf32_Rel *)s->data_ptr;
rel++) {
int type, sym_index;
/* offset symbol index */
int type;
unsigned sym_index;
/* convert symbol index */
type = ELF32_R_TYPE(rel->r_info);
sym_index = ELF32_R_SYM(rel->r_info);
sym_index += offsetl;
/* NOTE: only one symtab assumed */
if (sym_index >= nb_syms)
goto invalid_reloc;
sym_index = old_to_new_syms[sym_index];
if (!sym_index) {
invalid_reloc:
error("Invalid relocation entry");
}
rel->r_info = ELF32_R_INFO(sym_index, type);
/* offset the relocation offset */
rel->r_offset += offseti;
@ -7275,12 +7397,93 @@ int tcc_load_object(TCCState *s1, const char *filename)
break;
}
}
free(symtab);
free(strtab);
free(old_to_new_syms);
free(sm_table);
free(shdr);
return 0;
}
int tcc_load_object(TCCState *s1, const char *filename)
{
FILE *f;
int ret;
f = fopen(filename, "r");
if (!f)
error("could not open '%s'", filename);
ret = tcc_load_object_file(s1, filename, f, 0);
fclose(f);
return ret;
}
#define ARMAG "!<arch>\012" /* For COFF and a.out archives */
typedef struct ArchiveHeader {
char ar_name[16]; /* name of this member */
char ar_date[12]; /* file mtime */
char ar_uid[6]; /* owner uid; printed as decimal */
char ar_gid[6]; /* owner gid; printed as decimal */
char ar_mode[8]; /* file mode, printed as octal */
char ar_size[10]; /* file size, printed as decimal */
char ar_fmag[2]; /* should contain ARFMAG */
} ArchiveHeader;
/* load a '.a' file */
int tcc_load_archive(TCCState *s1, const char *filename)
{
ArchiveHeader hdr;
char magic[8];
char ar_size[11];
char ar_name[17];
int size, len, i;
FILE *f;
unsigned long file_offset;
f = fopen(filename, "r");
if (!f)
error("could not open '%s'", filename);
len = fread(magic, 1, sizeof(magic), f);
if (len != sizeof(magic) ||
memcmp(magic, ARMAG, sizeof(magic)) != 0)
error("invalid archive magic");
for(;;) {
len = fread(&hdr, 1, sizeof(hdr), f);
if (len == 0)
break;
if (len != sizeof(hdr))
error("invalid archive");
memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size));
ar_size[sizeof(hdr.ar_size)] = '\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';
// printf("name='%s' size=%d %s\n", ar_name, size, ar_size);
file_offset = ftell(f);
if (!strcmp(ar_name, "/") ||
!strcmp(ar_name, "//") ||
!strcmp(ar_name, "__.SYMDEF") ||
!strcmp(ar_name, "__.SYMDEF/") ||
!strcmp(ar_name, "ARFILENAMES/")) {
/* skip symbol table or archive names */
} else {
tcc_load_object_file(s1, filename, f, file_offset);
}
/* align to even */
size = (size + 1) & ~1;
fseek(f, file_offset + size, SEEK_SET);
}
fclose(f);
return 0;
}
/* print the position in the source file of PC value 'pc' by reading
the stabs debug information */
static void rt_printline(unsigned long wanted_pc)
@ -7427,43 +7630,13 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
}
#endif
static void *resolve_sym(const char *sym)
{
#ifdef CONFIG_TCC_BCHECK
if (do_bounds_check) {
void *ptr;
ptr = bound_resolve_sym(sym);
if (ptr)
return ptr;
}
#endif
return dlsym(NULL, sym);
}
static void resolve_extern_syms(void)
{
unsigned long addr;
Elf32_Sym *sym;
const char *name;
for(sym = (Elf32_Sym *)symtab_section->data + 1;
sym < (Elf32_Sym *)symtab_section->data_ptr;
sym++) {
if (sym->st_shndx == SHN_UNDEF) {
name = symtab_section->link->data + sym->st_name;
addr = (unsigned long)resolve_sym(name);
if (!addr)
error("unresolved external reference '%s'", name);
sym->st_value = addr;
sym->st_shndx = SHN_ABS;
}
}
}
/* relocate all the code and data */
static void relocate_program(void)
/* launch the compiled program with the given arguments */
int tcc_run(TCCState *s1, int argc, char **argv)
{
Section *s;
int (*prog_main)(int, char **);
relocate_common_syms();
/* compute relocation address : section are relocated in place */
for(s = first_section; s != NULL; s = s->next) {
@ -7471,27 +7644,15 @@ static void relocate_program(void)
s->sh_addr = (unsigned long)s->data;
}
relocate_syms(1);
/* relocate each section */
for(s = first_section; s != NULL; s = s->next) {
if ((s->sh_flags & SHF_ALLOC) && s->reloc)
relocate_section(s);
}
}
/* launch the compiled program with the given arguments */
int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **);
int sym_index;
resolve_extern_syms();
relocate_program();
sym_index = find_elf_sym(symtab_section, "main");
if (!sym_index)
error("main() not defined");
prog_main = (void *)get_sym_val(sym_index);
prog_main = (void *)get_elf_sym_val("main");
if (do_debug) {
#ifdef WIN32
@ -7604,17 +7765,23 @@ void tcc_add_file(TCCState *s, const char *filename)
{
const char *p;
int ext;
/* find file type with extension */
p = strrchr(filename, '.');
if (!p)
ext = '\0';
else
ext = p[1];
if (ext == 'o') {
switch(ext) {
case 'o':
tcc_load_object(s, filename);
} else {
break;
case 'a':
tcc_load_archive(s, filename);
break;
default:
tcc_compile_file(s, filename);
break;
}
}
@ -7627,7 +7794,6 @@ void help(void)
"\n"
"General options:\n"
" -c compile only - generate an object file\n"
" -i infile compile infile\n"
" -o outfile set output filename (NOT WORKING YET)\n"
" -bench output compilation statistics\n"
" -- allows multiples input files if no -o option given. Also\n"
@ -7673,6 +7839,8 @@ int main(int argc, char **argv)
if (r[1] == '-') {
/* '--' enables multiple files input */
multiple_files = 1;
} else if (r[1] == 'h' || r[1] == '?') {
goto show_help;
} else if (r[1] == 'I') {
if (tcc_add_include_path(s, r + 2) < 0)
error("too many include paths");
@ -7744,6 +7912,13 @@ int main(int argc, char **argv)
}
}
/* add libc crt1/crti objects */
if (outfile && file_type != TCC_FILE_OBJ) {
if (file_type != TCC_FILE_DLL)
tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crt1.o");
tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crti.o");
}
tcc_add_file(s, argv[optind]);
if (multiple_files) {
while ((optind + 1) < argc) {
@ -7758,6 +7933,11 @@ int main(int argc, char **argv)
}
}
/* add libc crtn object */
if (outfile && file_type != TCC_FILE_OBJ) {
tcc_add_file(s, CONFIG_TCC_CRT_PREFIX "/crtn.o");
}
if (do_bench) {
printf("total: %d idents, %d lines, %d bytes\n",
tok_ident - TOK_IDENT, total_lines, total_bytes);