Alien-TinyCCx
view release on metacpan or search on metacpan
src/tccelf.c view on Meta::CPAN
found. */
ST_FUNC int find_elf_sym(Section *s, const char *name)
{
ElfW(Sym) *sym;
Section *hs;
int nbuckets, sym_index, h;
const char *name1;
hs = s->hash;
if (!hs)
return 0;
nbuckets = ((int *)hs->data)[0];
h = elf_hash((unsigned char *) name) % nbuckets;
sym_index = ((int *)hs->data)[2 + h];
while (sym_index != 0) {
sym = &((ElfW(Sym) *)s->data)[sym_index];
name1 = (char *) s->link->data + sym->st_name;
if (!strcmp(name, name1))
return sym_index;
sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
}
return 0;
}
/* return elf symbol value, signal error if 'err' is nonzero */
ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err)
{
int sym_index;
ElfW(Sym) *sym;
sym_index = find_elf_sym(s->symtab, name);
sym = &((ElfW(Sym) *)s->symtab->data)[sym_index];
if (!sym_index || sym->st_shndx == SHN_UNDEF) {
if (err)
tcc_error("%s not defined", name);
return 0;
}
return sym->st_value;
}
/* return elf symbol value */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name)
{
return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0);
}
#if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
/* return elf symbol value or error */
ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
{
return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1);
}
#endif
/* add an elf symbol : check if it is already defined and patch
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size,
int info, int other, int sh_num, const char *name)
{
ElfW(Sym) *esym;
int sym_bind, sym_index, sym_type, esym_bind;
unsigned char sym_vis, esym_vis, new_vis;
sym_bind = ELFW(ST_BIND)(info);
sym_type = ELFW(ST_TYPE)(info);
sym_vis = ELFW(ST_VISIBILITY)(other);
if (sym_bind != STB_LOCAL) {
/* we search global or weak symbols */
sym_index = find_elf_sym(s, name);
if (!sym_index)
goto do_def;
esym = &((ElfW(Sym) *)s->data)[sym_index];
if (esym->st_shndx != SHN_UNDEF) {
esym_bind = ELFW(ST_BIND)(esym->st_info);
/* propagate the most constraining visibility */
/* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */
esym_vis = ELFW(ST_VISIBILITY)(esym->st_other);
if (esym_vis == STV_DEFAULT) {
new_vis = sym_vis;
} else if (sym_vis == STV_DEFAULT) {
new_vis = esym_vis;
} else {
new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis;
}
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
| new_vis;
other = esym->st_other; /* in case we have to patch esym */
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 (sym_bind == STB_WEAK && esym_bind == STB_WEAK) {
/* keep first-found weak definition, ignore subsequents */
} else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) {
/* ignore hidden symbols after */
} else if ((esym->st_shndx == SHN_COMMON
|| esym->st_shndx == bss_section->sh_num)
&& (sh_num < SHN_LORESERVE
&& sh_num != bss_section->sh_num)) {
/* data symbol gets precedence over common/bss */
goto do_patch;
} else if (sh_num == SHN_COMMON || sh_num == bss_section->sh_num) {
/* data symbol keeps precedence over common/bss */
} else if (s == tcc_state->dynsymtab_section) {
/* we accept that two DLL define the same symbol */
} else {
#if 0
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis);
#endif
tcc_error_noabort("'%s' defined twice", name);
}
} else {
do_patch:
esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
esym->st_shndx = sh_num;
new_undef_sym = 1;
esym->st_value = value;
esym->st_size = size;
esym->st_other = other;
}
} else {
do_def:
sym_index = put_elf_sym(s, value, size,
ELFW(ST_INFO)(sym_bind, sym_type), other,
sh_num, name);
}
return sym_index;
}
/* put relocation */
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
int type, int symbol, addr_t addend)
{
char buf[256];
Section *sr;
ElfW_Rel *rel;
sr = s->reloc;
if (!sr) {
/* if no relocation section, create it */
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
/* if the symtab is allocated, then we consider the relocation
are also */
sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
s->reloc = sr;
}
rel = section_ptr_add(sr, sizeof(ElfW_Rel));
rel->r_offset = offset;
rel->r_info = ELFW(R_INFO)(symbol, type);
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
rel->r_addend = addend;
#else
if (addend)
tcc_error("non-zero addend on REL architecture");
#endif
}
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
int type, int symbol)
{
put_elf_reloca(symtab, s, offset, type, symbol, 0);
}
/* put stab debug information */
ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
unsigned long value)
{
Stab_Sym *sym;
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
if (str) {
sym->n_strx = put_elf_str(stabstr_section, str);
} else {
sym->n_strx = 0;
}
sym->n_type = type;
sym->n_other = other;
sym->n_desc = desc;
sym->n_value = value;
}
src/tccelf.c view on Meta::CPAN
p++;
}
/* save the number of local symbols in section header */
s->sh_info = q - new_syms;
/* then second pass for non local symbols */
p = (ElfW(Sym) *)s->data;
for(i = 0; i < nb_syms; i++) {
if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) {
old_to_new_syms[i] = q - new_syms;
*q++ = *p;
}
p++;
}
/* we copy the new symbols to the old */
memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym)));
tcc_free(new_syms);
/* now we modify all the relocations */
for(i = 1; i < s1->nb_sections; i++) {
sr = s1->sections[i];
if (sr->sh_type == SHT_RELX && sr->link == s) {
for_each_elem(sr, 0, rel, ElfW_Rel) {
sym_index = ELFW(R_SYM)(rel->r_info);
type = ELFW(R_TYPE)(rel->r_info);
sym_index = old_to_new_syms[sym_index];
rel->r_info = ELFW(R_INFO)(sym_index, type);
}
}
}
tcc_free(old_to_new_syms);
}
/* relocate common symbols in the .bss section */
ST_FUNC void relocate_common_syms(void)
{
ElfW(Sym) *sym;
unsigned long offset, align;
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (sym->st_shndx == SHN_COMMON) {
/* align symbol */
align = sym->st_value;
offset = bss_section->data_offset;
offset = (offset + align - 1) & -align;
sym->st_value = offset;
sym->st_shndx = bss_section->sh_num;
offset += sym->st_size;
bss_section->data_offset = offset;
}
}
}
/* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */
ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
{
ElfW(Sym) *sym, *esym;
int sym_bind, sh_num, sym_index;
const char *name;
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
sh_num = sym->st_shndx;
if (sh_num == SHN_UNDEF) {
name = (char *) strtab_section->data + sym->st_name;
/* Use ld.so to resolve symbol for us (for tcc -run) */
if (do_resolve) {
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
void *addr;
name = (char *) symtab_section->link->data + sym->st_name;
addr = dlsym(RTLD_DEFAULT, name);
if (addr) {
sym->st_value = (addr_t)addr;
#ifdef DEBUG_RELOC
printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value);
#endif
goto found;
}
#endif
} else if (s1->dynsym) {
/* if dynamic symbol exist, then use it */
sym_index = find_elf_sym(s1->dynsym, name);
if (sym_index) {
esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index];
sym->st_value = esym->st_value;
goto found;
}
}
/* XXX: _fp_hw seems to be part of the ABI, so we ignore
it */
if (!strcmp(name, "_fp_hw"))
goto found;
/* only weak symbols are accepted to be undefined. Their
value is zero */
sym_bind = ELFW(ST_BIND)(sym->st_info);
if (sym_bind == STB_WEAK) {
sym->st_value = 0;
} else {
tcc_error_noabort("undefined symbol '%s'", name);
}
} else if (sh_num < SHN_LORESERVE) {
/* add section base */
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
}
found: ;
}
}
/* relocate a given section (CPU dependent) by applying the relocations
in the associated relocation section */
ST_FUNC void relocate_section(TCCState *s1, Section *s)
{
Section *sr = s->reloc;
ElfW_Rel *rel;
ElfW(Sym) *sym;
int type, sym_index;
unsigned char *ptr;
addr_t val, addr;
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ElfW_Rel *qrel = (ElfW_Rel *) sr->data; /* ptr to next reloc entry reused */
int esym_index;
#endif
for_each_elem(sr, 0, rel, ElfW_Rel) {
ptr = s->data + rel->r_offset;
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
val = sym->st_value;
#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64)
val += rel->r_addend;
#endif
type = ELFW(R_TYPE)(rel->r_info);
addr = s->sh_addr + rel->r_offset;
/* CPU specific */
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_32:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->symtab_to_dynsym[sym_index];
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32);
qrel++;
break;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
qrel++;
}
}
add32le(ptr, val);
break;
case R_386_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
src/tccelf.c view on Meta::CPAN
/* zero plt offsets of weak symbols in .dynsym */
static void patch_dynsym_undef(TCCState *s1, Section *s)
{
ElfW(Sym) *sym;
for_each_elem(s, 1, sym, ElfW(Sym))
if (sym->st_shndx == SHN_UNDEF && ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
sym->st_value = 0;
}
#endif
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
{
int sym_index = ELFW(R_SYM) (rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
unsigned long offset;
if (sym_index >= s1->nb_sym_attrs)
return;
offset = s1->sym_attrs[sym_index].got_offset;
section_reserve(s1->got, offset + PTR_SIZE);
#ifdef TCC_TARGET_X86_64
/* only works for x86-64 */
write32le(s1->got->data + offset + 4, sym->st_value >> 32);
#endif
write32le(s1->got->data + offset, sym->st_value & 0xffffffff);
}
/* Perform relocation to GOT or PLT entries */
ST_FUNC void fill_got(TCCState *s1)
{
Section *s;
ElfW_Rel *rel;
int i;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_type != SHT_RELX)
continue;
/* no need to handle got relocations */
if (s->link != symtab_section)
continue;
for_each_elem(s, 0, rel, ElfW_Rel) {
switch (ELFW(R_TYPE) (rel->r_info)) {
case R_X86_64_GOT32:
case R_X86_64_GOTPCREL:
case R_X86_64_GOTPCRELX:
case R_X86_64_REX_GOTPCRELX:
case R_X86_64_PLT32:
fill_got_entry(s1, rel);
break;
}
}
}
}
/* Bind symbols of executable: resolve undefined symbols from exported symbols
in shared libraries and export non local defined symbols to shared libraries
if -rdynamic switch was given on command line */
static void bind_exe_dynsyms(TCCState *s1)
{
const char *name;
int sym_index, index;
ElfW(Sym) *sym, *esym;
int type;
/* Resolve undefined symbols from dynamic symbols. When there is a match:
- if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT
- if STT_OBJECT symbol -> add it in .bss section with suitable reloc */
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (sym->st_shndx == SHN_UNDEF) {
name = (char *) symtab_section->link->data + sym->st_name;
sym_index = find_elf_sym(s1->dynsymtab_section, name);
if (sym_index) {
esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index];
type = ELFW(ST_TYPE)(esym->st_info);
if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) {
/* Indirect functions shall have STT_FUNC type in executable
* dynsym section. Indeed, a dlsym call following a lazy
* resolution would pick the symbol value from the
* executable dynsym entry which would contain the address
* of the function wanted by the caller of dlsym instead of
* the address of the function that would return that
* address */
put_got_entry(s1, R_JMP_SLOT, esym->st_size,
ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC),
sym - (ElfW(Sym) *)symtab_section->data);
} else if (type == STT_OBJECT) {
unsigned long offset;
ElfW(Sym) *dynsym;
offset = bss_section->data_offset;
/* XXX: which alignment ? */
offset = (offset + 16 - 1) & -16;
index = put_elf_sym(s1->dynsym, offset, esym->st_size,
esym->st_info, 0, bss_section->sh_num,
name);
/* Ensure R_COPY works for weak symbol aliases */
if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) {
for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) {
if ((dynsym->st_value == esym->st_value)
&& (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) {
char *dynname = (char *) s1->dynsymtab_section->link->data
+ dynsym->st_name;
put_elf_sym(s1->dynsym, offset, dynsym->st_size,
dynsym->st_info, 0,
bss_section->sh_num, dynname);
break;
}
}
}
put_elf_reloc(s1->dynsym, bss_section,
offset, R_COPY, index);
offset += esym->st_size;
bss_section->data_offset = offset;
}
} else {
/* STB_WEAK undefined symbols are accepted */
/* XXX: _fp_hw seems to be part of the ABI, so we ignore it */
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
!strcmp(name, "_fp_hw")) {
} else {
tcc_error_noabort("undefined symbol '%s'", name);
}
}
} else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
name = (char *) symtab_section->link->data + sym->st_name;
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
0, sym->st_shndx, name);
}
}
}
/* Bind symbols of libraries: export non local symbols of executable that
resolve undefined symbols of shared libraries */
static void bind_libs_dynsyms(TCCState *s1)
{
const char *name;
int sym_index;
ElfW(Sym) *sym, *esym;
/* now look at unresolved dynamic symbols and export
corresponding symbol */
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
sym_index = find_elf_sym(symtab_section, name);
if (sym_index) {
/* XXX: avoid adding a symbol if already present because of
-rdynamic ? */
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
if (sym->st_shndx != SHN_UNDEF)
put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name);
} else if (esym->st_shndx == SHN_UNDEF) {
/* weak symbols can stay undefined */
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
tcc_warning("undefined dynamic symbol '%s'", name);
}
}
}
/* Export all non local symbols (for shared libraries) */
static void export_global_syms(TCCState *s1)
{
int nb_syms, dynindex, index;
const char *name;
ElfW(Sym) *sym;
nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym));
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
name = (char *) symtab_section->link->data + sym->st_name;
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name);
index = sym - (ElfW(Sym) *) symtab_section->data;
s1->symtab_to_dynsym[index] = dynindex;
}
}
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final
address for PLT and GOT are known (see fill_program_header) */
ST_FUNC void relocate_plt(TCCState *s1)
{
uint8_t *p, *p_end;
if (!s1->plt)
return;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
#if defined(TCC_TARGET_I386)
add32le(p + 2, s1->got->sh_addr);
add32le(p + 8, s1->got->sh_addr);
src/tccelf.c view on Meta::CPAN
return 0;
}
/* Output an elf, coff or binary file */
/* XXX: suppress unneeded sections */
static int elf_output_file(TCCState *s1, const char *filename)
{
int i, ret, phnum, shnum, file_type, file_offset, *sec_order;
struct dyn_inf dyninf;
ElfW(Phdr) *phdr;
ElfW(Sym) *sym;
Section *strsec, *interp, *dynamic, *dynstr;
file_type = s1->output_type;
s1->nb_errors = 0;
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
if (file_type != TCC_OUTPUT_OBJ) {
tcc_add_runtime(s1);
}
phdr = NULL;
sec_order = NULL;
interp = dynamic = dynstr = NULL; /* avoid warning */
dyninf.dyn_rel_off = 0; /* avoid warning */
if (file_type != TCC_OUTPUT_OBJ) {
relocate_common_syms();
tcc_add_linker_symbols(s1);
if (!s1->static_link) {
if (file_type == TCC_OUTPUT_EXE) {
char *ptr;
/* allow override the dynamic loader */
const char *elfint = getenv("LD_SO");
if (elfint == NULL)
elfint = DEFAULT_ELFINTERP(s1);
/* add interpreter section only if executable */
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
interp->sh_addralign = 1;
ptr = section_ptr_add(interp, 1 + strlen(elfint));
strcpy(ptr, elfint);
}
/* add dynamic symbol table */
s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC,
".dynstr",
".hash", SHF_ALLOC);
dynstr = s1->dynsym->link;
/* add dynamic section */
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
SHF_ALLOC | SHF_WRITE);
dynamic->link = dynstr;
dynamic->sh_entsize = sizeof(ElfW(Dyn));
build_got(s1);
if (file_type == TCC_OUTPUT_EXE) {
bind_exe_dynsyms(s1);
if (s1->nb_errors) {
ret = -1;
goto the_end;
}
bind_libs_dynsyms(s1);
} else /* shared library case: simply export all global symbols */
export_global_syms(s1);
build_got_entries(s1);
/* add a list of needed dlls */
for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i];
if (dllref->level == 0)
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
}
if (s1->rpath)
put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath));
/* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */
if (file_type == TCC_OUTPUT_DLL) {
if (s1->soname)
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
put_dt(dynamic, DT_TEXTREL, 0);
}
if (s1->symbolic)
put_dt(dynamic, DT_SYMBOLIC, 0);
/* add necessary space for other entries */
dyninf.dyn_rel_off = dynamic->data_offset;
dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS;
} else {
/* still need to build got entries in case of static link */
build_got_entries(s1);
}
}
/* we add a section for symbols */
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
put_elf_str(strsec, "");
/* compute number of sections */
shnum = s1->nb_sections;
/* this array is used to reorder sections in the output file */
sec_order = tcc_malloc(sizeof(int) * shnum);
sec_order[0] = 0;
/* compute number of program headers */
switch(file_type) {
default:
case TCC_OUTPUT_OBJ:
phnum = 0;
break;
case TCC_OUTPUT_EXE:
if (!s1->static_link)
phnum = 4 + HAVE_PHDR;
else
phnum = 2;
break;
case TCC_OUTPUT_DLL:
phnum = 3;
src/tccelf.c view on Meta::CPAN
/* load a '.a' file */
ST_FUNC int tcc_load_archive(TCCState *s1, int fd)
{
ArchiveHeader hdr;
char ar_size[11];
char ar_name[17];
char magic[8];
int size, len, i;
unsigned long file_offset;
/* skip magic which was already checked */
read(fd, magic, sizeof(magic));
for(;;) {
len = read(fd, &hdr, sizeof(hdr));
if (len == 0)
break;
if (len != sizeof(hdr)) {
tcc_error_noabort("invalid archive");
return -1;
}
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';
file_offset = lseek(fd, 0, SEEK_CUR);
/* align to even */
size = (size + 1) & ~1;
if (!strcmp(ar_name, "/")) {
/* coff symbol table : we handle it */
if(s1->alacarte_link)
return tcc_load_alacarte(s1, fd, size, 4);
} else if (!strcmp(ar_name, "/SYM64/")) {
if(s1->alacarte_link)
return tcc_load_alacarte(s1, fd, size, 8);
} else {
ElfW(Ehdr) ehdr;
if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
if (tcc_load_object_file(s1, fd, file_offset) < 0)
return -1;
}
}
lseek(fd, file_offset + size, SEEK_SET);
}
return 0;
}
#ifndef TCC_TARGET_PE
/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
is referenced by the user (so it should be added as DT_NEEDED in
the generated ELF file) */
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
{
ElfW(Ehdr) ehdr;
ElfW(Shdr) *shdr, *sh, *sh1;
int i, j, nb_syms, nb_dts, sym_bind, ret;
ElfW(Sym) *sym, *dynsym;
ElfW(Dyn) *dt, *dynamic;
unsigned char *dynstr;
const char *name, *soname;
DLLReference *dllref;
read(fd, &ehdr, sizeof(ehdr));
/* test CPU specific stuff */
if (ehdr.e_ident[5] != ELFDATA2LSB ||
ehdr.e_machine != EM_TCC_TARGET) {
tcc_error_noabort("bad architecture");
return -1;
}
/* read sections */
shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum);
/* load dynamic section and dynamic symbols */
nb_syms = 0;
nb_dts = 0;
dynamic = NULL;
dynsym = NULL; /* avoid warning */
dynstr = NULL; /* avoid warning */
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
switch(sh->sh_type) {
case SHT_DYNAMIC:
nb_dts = sh->sh_size / sizeof(ElfW(Dyn));
dynamic = load_data(fd, sh->sh_offset, sh->sh_size);
break;
case SHT_DYNSYM:
nb_syms = sh->sh_size / sizeof(ElfW(Sym));
dynsym = load_data(fd, sh->sh_offset, sh->sh_size);
sh1 = &shdr[sh->sh_link];
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
break;
default:
break;
}
}
/* compute the real library name */
soname = tcc_basename(filename);
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
if (dt->d_tag == DT_SONAME) {
soname = (char *) dynstr + dt->d_un.d_val;
}
}
/* if the dll is already loaded, do not load it */
for(i = 0; i < s1->nb_loaded_dlls; i++) {
dllref = s1->loaded_dlls[i];
if (!strcmp(soname, dllref->name)) {
/* but update level if needed */
if (level < dllref->level)
dllref->level = level;
ret = 0;
goto the_end;
}
}
/* add the dll and its level */
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
dllref->level = level;
strcpy(dllref->name, soname);
dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
/* add dynamic symbols in dynsym_section */
for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
sym_bind = ELFW(ST_BIND)(sym->st_info);
if (sym_bind == STB_LOCAL)
continue;
name = (char *) dynstr + sym->st_name;
add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
sym->st_info, sym->st_other, sym->st_shndx, name);
}
/* load all referenced DLLs */
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
switch(dt->d_tag) {
case DT_NEEDED:
name = (char *) dynstr + dt->d_un.d_val;
for(j = 0; j < s1->nb_loaded_dlls; j++) {
dllref = s1->loaded_dlls[j];
if (!strcmp(name, dllref->name))
goto already_loaded;
}
if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) {
tcc_error_noabort("referenced dll '%s' not found", name);
ret = -1;
goto the_end;
}
already_loaded:
break;
}
}
ret = 0;
the_end:
tcc_free(dynstr);
tcc_free(dynsym);
tcc_free(dynamic);
tcc_free(shdr);
return ret;
}
#define LD_TOK_NAME 256
#define LD_TOK_EOF (-1)
/* return next ld script token */
static int ld_next(TCCState *s1, char *name, int name_size)
{
int c;
char *q;
redo:
switch(ch) {
case ' ':
case '\t':
case '\f':
case '\v':
case '\r':
case '\n':
inp();
goto redo;
case '/':
minp();
if (ch == '*') {
file->buf_ptr = parse_comment(file->buf_ptr);
ch = file->buf_ptr[0];
goto redo;
} else {
( run in 0.490 second using v1.01-cache-2.11-cpan-2398b32b56e )