mirror of
https://github.com/frida/tinycc
synced 2024-12-24 22:16:49 +03:00
Add elf version support
This commit is contained in:
parent
491773ac58
commit
7268fe7239
372
tccelf.c
372
tccelf.c
@ -42,6 +42,34 @@ ST_DATA Section *symtab_section;
|
|||||||
/* debug sections */
|
/* debug sections */
|
||||||
ST_DATA Section *stab_section, *stabstr_section;
|
ST_DATA Section *stab_section, *stabstr_section;
|
||||||
|
|
||||||
|
/* elf version information */
|
||||||
|
ST_DATA int nb_version_sym;
|
||||||
|
struct sym_info_struct {
|
||||||
|
char *name;
|
||||||
|
ElfW(Sym) esym;
|
||||||
|
};
|
||||||
|
ST_DATA struct def_need_struct {
|
||||||
|
char *lib;
|
||||||
|
char *version;
|
||||||
|
unsigned int nb_sym_info;
|
||||||
|
struct sym_info_struct *sym_info;
|
||||||
|
} *version_sym;
|
||||||
|
ST_DATA int nb_need;
|
||||||
|
ST_DATA int dt_verneednum;
|
||||||
|
ST_DATA struct need_struct {
|
||||||
|
int offset;
|
||||||
|
char *lib;
|
||||||
|
int n_aux;
|
||||||
|
struct aux_struct {
|
||||||
|
int offset;
|
||||||
|
char *version;
|
||||||
|
int other;
|
||||||
|
} *aux;
|
||||||
|
} *need;
|
||||||
|
ST_DATA ElfW(Half) next_version = 1;
|
||||||
|
ST_DATA Section *versym_section;
|
||||||
|
ST_DATA Section *verneed_section;
|
||||||
|
|
||||||
/* XXX: avoid static variable */
|
/* XXX: avoid static variable */
|
||||||
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
|
static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
|
||||||
|
|
||||||
@ -61,6 +89,10 @@ ST_FUNC void tccelf_new(TCCState *s)
|
|||||||
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
||||||
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
||||||
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||||
|
versym_section = new_section(s, ".gnu.version", SHT_GNU_versym, SHF_ALLOC);
|
||||||
|
versym_section->sh_entsize = sizeof(ElfW(Half));
|
||||||
|
verneed_section = new_section(s, ".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC);
|
||||||
|
verneed_section->sh_info = 2;
|
||||||
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
|
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
|
||||||
common_section->sh_num = SHN_COMMON;
|
common_section->sh_num = SHN_COMMON;
|
||||||
|
|
||||||
@ -198,13 +230,18 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh
|
|||||||
sec->sh_type = sh_type;
|
sec->sh_type = sh_type;
|
||||||
sec->sh_flags = sh_flags;
|
sec->sh_flags = sh_flags;
|
||||||
switch(sh_type) {
|
switch(sh_type) {
|
||||||
|
case SHT_GNU_versym:
|
||||||
|
sec->sh_addralign = 2;
|
||||||
|
break;
|
||||||
case SHT_HASH:
|
case SHT_HASH:
|
||||||
case SHT_REL:
|
case SHT_REL:
|
||||||
case SHT_RELA:
|
case SHT_RELA:
|
||||||
case SHT_DYNSYM:
|
case SHT_DYNSYM:
|
||||||
case SHT_SYMTAB:
|
case SHT_SYMTAB:
|
||||||
case SHT_DYNAMIC:
|
case SHT_DYNAMIC:
|
||||||
sec->sh_addralign = 4;
|
case SHT_GNU_verneed:
|
||||||
|
case SHT_GNU_verdef:
|
||||||
|
sec->sh_addralign = PTR_SIZE;
|
||||||
break;
|
break;
|
||||||
case SHT_STRTAB:
|
case SHT_STRTAB:
|
||||||
sec->sh_addralign = 1;
|
sec->sh_addralign = 1;
|
||||||
@ -516,6 +553,220 @@ ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ST_FUNC void
|
||||||
|
save_def_need_index (int *n_def_need, struct def_need_struct **def_need,
|
||||||
|
unsigned int n, const char *lib, const char *version)
|
||||||
|
{
|
||||||
|
/* add index in table */
|
||||||
|
if (*n_def_need < n + 1) {
|
||||||
|
*def_need = (struct def_need_struct *)
|
||||||
|
tcc_realloc (*def_need,
|
||||||
|
(n + 1) * sizeof (struct def_need_struct));
|
||||||
|
while (*n_def_need < n + 1) {
|
||||||
|
(*def_need)[*n_def_need].lib = NULL;
|
||||||
|
(*def_need)[*n_def_need].version = NULL;
|
||||||
|
(*def_need)[*n_def_need].nb_sym_info = 0;
|
||||||
|
(*def_need)[*n_def_need].sym_info = NULL;
|
||||||
|
(*n_def_need)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((*def_need)[n].lib == NULL) {
|
||||||
|
(*def_need)[n].lib = tcc_strdup (lib);
|
||||||
|
(*def_need)[n].version = tcc_strdup (version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ST_FUNC void
|
||||||
|
free_def_need (int n_def_need, struct def_need_struct *def_need)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_def_need; i++) {
|
||||||
|
tcc_free (def_need[i].lib);
|
||||||
|
tcc_free (def_need[i].version);
|
||||||
|
}
|
||||||
|
tcc_free (def_need);
|
||||||
|
}
|
||||||
|
|
||||||
|
ST_FUNC void
|
||||||
|
add_version_sym (Section *s, int sym_index, int n_def_need,
|
||||||
|
struct def_need_struct *def_need, const char *name, unsigned int n)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
ElfW(Sym) *esym;
|
||||||
|
|
||||||
|
/* check if present */
|
||||||
|
esym = &((ElfW(Sym) *)s->data)[sym_index];
|
||||||
|
for (i = 0; i < nb_version_sym; i++) {
|
||||||
|
for (j = 0; j < version_sym[i].nb_sym_info; j++) {
|
||||||
|
if (strcmp (version_sym[i].sym_info[j].name, name) == 0) {
|
||||||
|
if (memcmp (&version_sym[i].sym_info[j].esym, esym, sizeof (ElfW(Sym))) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
version_sym[i].nb_sym_info--;
|
||||||
|
tcc_free (version_sym[i].sym_info[j].name);
|
||||||
|
for (; j < version_sym[i].nb_sym_info; j++) {
|
||||||
|
version_sym[i].sym_info[j] = version_sym[i].sym_info[j + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* add new value */
|
||||||
|
for (i = 0; i < nb_version_sym; i++) {
|
||||||
|
if (strcmp (def_need[n].lib,
|
||||||
|
version_sym[i].lib) == 0 &&
|
||||||
|
strcmp (def_need[n].version,
|
||||||
|
version_sym[i].version) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == nb_version_sym) {
|
||||||
|
version_sym = (struct def_need_struct *)
|
||||||
|
tcc_realloc (version_sym,
|
||||||
|
(nb_version_sym + 1) * sizeof (struct def_need_struct));
|
||||||
|
version_sym[nb_version_sym].lib = tcc_strdup (def_need[n].lib);
|
||||||
|
version_sym[nb_version_sym].version = tcc_strdup (def_need[n].version);
|
||||||
|
version_sym[nb_version_sym].nb_sym_info = 0;
|
||||||
|
version_sym[nb_version_sym].sym_info = NULL;
|
||||||
|
nb_version_sym++;
|
||||||
|
}
|
||||||
|
version_sym[i].sym_info = (struct sym_info_struct *)
|
||||||
|
tcc_realloc (version_sym[i].sym_info,
|
||||||
|
(version_sym[i].nb_sym_info + 1) * sizeof (struct sym_info_struct));
|
||||||
|
version_sym[i].sym_info[version_sym[i].nb_sym_info].name = tcc_strdup (name);
|
||||||
|
version_sym[i].sym_info[version_sym[i].nb_sym_info].esym = *esym;
|
||||||
|
version_sym[i].nb_sym_info++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_need_sym (Section *s, const char *soname, const char *version, const char *name, int sym_index)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long size;
|
||||||
|
void *ptr;
|
||||||
|
int ver_index = 0;
|
||||||
|
struct need_struct *verlib = NULL;
|
||||||
|
ElfW(Half) vers;
|
||||||
|
|
||||||
|
if (soname) {
|
||||||
|
for (i = 0; i < nb_need; i++) {
|
||||||
|
if (strcmp (soname, need[i].lib) == 0) {
|
||||||
|
verlib = &need[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (verlib == NULL) {
|
||||||
|
need = (struct need_struct *)
|
||||||
|
tcc_realloc (need, (nb_need + 1) * sizeof (struct need_struct));
|
||||||
|
need[nb_need].offset = put_elf_str(s->link, soname);
|
||||||
|
need[nb_need].lib = tcc_strdup (soname);
|
||||||
|
need[nb_need].n_aux = 0;
|
||||||
|
need[nb_need].aux = NULL;
|
||||||
|
verlib = &need[nb_need];
|
||||||
|
nb_need++;
|
||||||
|
}
|
||||||
|
for (i = 0; i < verlib->n_aux; i++) {
|
||||||
|
if (strcmp (version, verlib->aux[i].version) == 0) {
|
||||||
|
ver_index = verlib->aux[i].other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ver_index == 0) {
|
||||||
|
verlib->aux = (struct aux_struct *)
|
||||||
|
tcc_realloc (verlib->aux, (verlib->n_aux + 1) * sizeof (struct aux_struct));
|
||||||
|
verlib->aux[verlib->n_aux].offset = put_elf_str(s->link, version);
|
||||||
|
verlib->aux[verlib->n_aux].version = tcc_strdup (version);
|
||||||
|
ver_index = verlib->aux[verlib->n_aux].other = ++next_version;
|
||||||
|
verlib->n_aux++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* update versym section */
|
||||||
|
size = versym_section->data_offset / sizeof (vers);
|
||||||
|
for (i = size; i < (sym_index + 1); i++) {
|
||||||
|
ptr = section_ptr_add (versym_section, sizeof (vers));
|
||||||
|
vers = 0;
|
||||||
|
memcpy (ptr, &vers, sizeof (vers));
|
||||||
|
}
|
||||||
|
ptr = versym_section->data + sym_index * sizeof (vers);
|
||||||
|
vers = ver_index;
|
||||||
|
memcpy (ptr, &vers, sizeof (vers));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
version_add (TCCState *s)
|
||||||
|
{
|
||||||
|
int i, j, found;
|
||||||
|
ElfW(Sym) *sym;
|
||||||
|
ElfW(Verneed) verneed;
|
||||||
|
ElfW(Vernaux) aux;
|
||||||
|
Section *symtab;
|
||||||
|
int sym_index, end_sym;
|
||||||
|
const char *name;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
/* add needed symbols */
|
||||||
|
symtab = s->dynsym;
|
||||||
|
end_sym = symtab->data_offset / sizeof (ElfSym);
|
||||||
|
for (sym_index = 0; sym_index < end_sym; ++sym_index) {
|
||||||
|
sym = &((ElfW(Sym) *)symtab->data)[sym_index];
|
||||||
|
name = (char *) symtab->link->data + sym->st_name;
|
||||||
|
found = 0;
|
||||||
|
for (i = 0; !found && i < nb_version_sym; i++) {
|
||||||
|
for (j = 0; !found && j < version_sym[i].nb_sym_info; j++) {
|
||||||
|
if (strcmp (version_sym[i].sym_info[j].name, name) == 0) {
|
||||||
|
found = 1;
|
||||||
|
add_need_sym (symtab, version_sym[i].lib, version_sym[i].version, name, sym_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
add_need_sym (symtab, NULL, NULL, NULL, sym_index);
|
||||||
|
}
|
||||||
|
symtab = s->dynsym; /* symtab can be realocated by add_need_sym */
|
||||||
|
}
|
||||||
|
/* generate verneed section */
|
||||||
|
for (i = 0; i < nb_need; i++) {
|
||||||
|
verneed.vn_version = 1;
|
||||||
|
verneed.vn_cnt = need[i].n_aux;
|
||||||
|
verneed.vn_file = need[i].offset;
|
||||||
|
verneed.vn_aux = sizeof (verneed);
|
||||||
|
verneed.vn_next = i == nb_need - 1 ? 0 : sizeof (verneed) + need[i].n_aux * sizeof (aux);
|
||||||
|
ptr = section_ptr_add (verneed_section, sizeof (verneed));
|
||||||
|
memcpy (ptr, &verneed, sizeof (verneed));
|
||||||
|
for (j = 0; j < need[i].n_aux; j++) {
|
||||||
|
aux.vna_hash = elf_hash (need[i].aux[j].version);
|
||||||
|
aux.vna_flags = 0;
|
||||||
|
aux.vna_other = need[i].aux[j].other;
|
||||||
|
aux.vna_name = need[i].aux[j].offset;
|
||||||
|
aux.vna_next = j == need[i].n_aux - 1 ? 0 : sizeof (aux);
|
||||||
|
ptr = section_ptr_add (verneed_section, sizeof (aux));
|
||||||
|
memcpy (ptr, &aux, sizeof (aux));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* free all info */
|
||||||
|
for (i = 0; i < nb_version_sym; i++) {
|
||||||
|
for (j = 0; j < version_sym[i].nb_sym_info; j++) {
|
||||||
|
tcc_free (version_sym[i].sym_info[j].name);
|
||||||
|
}
|
||||||
|
tcc_free (version_sym[i].lib);
|
||||||
|
tcc_free (version_sym[i].version);
|
||||||
|
tcc_free (version_sym[i].sym_info);
|
||||||
|
}
|
||||||
|
tcc_free (version_sym);
|
||||||
|
nb_version_sym = 0;
|
||||||
|
version_sym = NULL;
|
||||||
|
for (i = 0; i < nb_need; i++) {
|
||||||
|
tcc_free (need[i].lib);
|
||||||
|
for (j = 0; j < need[i].n_aux; j++) {
|
||||||
|
tcc_free (need[i].aux[j].version);
|
||||||
|
}
|
||||||
|
tcc_free (need[i].aux);
|
||||||
|
}
|
||||||
|
tcc_free (need);
|
||||||
|
dt_verneednum = nb_need;
|
||||||
|
nb_need = 0;
|
||||||
|
need = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* add an elf symbol : check if it is already defined and patch
|
/* add an elf symbol : check if it is already defined and patch
|
||||||
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
|
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
|
||||||
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
|
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
|
||||||
@ -1855,6 +2106,9 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
|
|||||||
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
|
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
|
||||||
|
put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
|
||||||
|
put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
|
||||||
if (s1->do_debug)
|
if (s1->do_debug)
|
||||||
put_dt(dynamic, DT_DEBUG, 0);
|
put_dt(dynamic, DT_DEBUG, 0);
|
||||||
put_dt(dynamic, DT_NULL, 0);
|
put_dt(dynamic, DT_NULL, 0);
|
||||||
@ -2137,6 +2391,8 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||||||
".dynstr",
|
".dynstr",
|
||||||
".hash", SHF_ALLOC);
|
".hash", SHF_ALLOC);
|
||||||
dynstr = s1->dynsym->link;
|
dynstr = s1->dynsym->link;
|
||||||
|
versym_section->link = s1->dynsym;
|
||||||
|
verneed_section->link = dynstr;
|
||||||
|
|
||||||
/* add dynamic section */
|
/* add dynamic section */
|
||||||
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
|
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
|
||||||
@ -2157,6 +2413,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
build_got_entries(s1);
|
build_got_entries(s1);
|
||||||
|
version_add (s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we add a section for symbols */
|
/* we add a section for symbols */
|
||||||
@ -2752,7 +3009,16 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
int i, j, nb_syms, nb_dts, sym_bind, ret;
|
int i, j, nb_syms, nb_dts, sym_bind, ret;
|
||||||
ElfW(Sym) *sym, *dynsym;
|
ElfW(Sym) *sym, *dynsym;
|
||||||
ElfW(Dyn) *dt, *dynamic;
|
ElfW(Dyn) *dt, *dynamic;
|
||||||
|
int nb_versyms;
|
||||||
|
ElfW(Verdef) *verdef, *vdef;
|
||||||
|
ElfW(Verneed) *verneed, *vneed;
|
||||||
|
ElfW(Half) *versym, *vsym;
|
||||||
unsigned char *dynstr;
|
unsigned char *dynstr;
|
||||||
|
uint32_t next;
|
||||||
|
int sym_index;
|
||||||
|
char *lib, *version;
|
||||||
|
int n_def_need = 0;
|
||||||
|
struct def_need_struct *def_need = NULL;
|
||||||
const char *name, *soname;
|
const char *name, *soname;
|
||||||
DLLReference *dllref;
|
DLLReference *dllref;
|
||||||
|
|
||||||
@ -2774,6 +3040,10 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
dynamic = NULL;
|
dynamic = NULL;
|
||||||
dynsym = NULL; /* avoid warning */
|
dynsym = NULL; /* avoid warning */
|
||||||
dynstr = NULL; /* avoid warning */
|
dynstr = NULL; /* avoid warning */
|
||||||
|
nb_versyms = 0;
|
||||||
|
verdef = NULL;
|
||||||
|
verneed = NULL;
|
||||||
|
versym = NULL;
|
||||||
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
|
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
|
||||||
switch(sh->sh_type) {
|
switch(sh->sh_type) {
|
||||||
case SHT_DYNAMIC:
|
case SHT_DYNAMIC:
|
||||||
@ -2786,6 +3056,16 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
sh1 = &shdr[sh->sh_link];
|
sh1 = &shdr[sh->sh_link];
|
||||||
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
|
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
|
||||||
break;
|
break;
|
||||||
|
case SHT_GNU_verdef:
|
||||||
|
verdef = load_data(fd, sh->sh_offset, sh->sh_size);
|
||||||
|
break;
|
||||||
|
case SHT_GNU_verneed:
|
||||||
|
verneed = load_data(fd, sh->sh_offset, sh->sh_size);
|
||||||
|
break;
|
||||||
|
case SHT_GNU_versym:
|
||||||
|
nb_versyms = sh->sh_size / sizeof(ElfW(Half));
|
||||||
|
versym = load_data(fd, sh->sh_offset, sh->sh_size);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2812,6 +3092,81 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nb_versyms != nb_syms) {
|
||||||
|
tcc_free (versym);
|
||||||
|
versym = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEBUG_VERSION 0
|
||||||
|
|
||||||
|
if (versym && verdef) {
|
||||||
|
lib = NULL;
|
||||||
|
vdef = verdef;
|
||||||
|
do {
|
||||||
|
ElfW(Verdaux) *verdaux =
|
||||||
|
(ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux);
|
||||||
|
|
||||||
|
#if DEBUG_VERSION
|
||||||
|
printf ("verdef: version:%u flags:%u index:%u, hash:%u\n",
|
||||||
|
vdef->vd_version, vdef->vd_flags, vdef->vd_ndx,
|
||||||
|
vdef->vd_hash);
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < vdef->vd_cnt; i++) {
|
||||||
|
version = (char *) dynstr + verdaux->vda_name;
|
||||||
|
|
||||||
|
if (lib == NULL) {
|
||||||
|
lib = version;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
save_def_need_index (&n_def_need, &def_need,
|
||||||
|
vdef->vd_ndx, lib, version);
|
||||||
|
}
|
||||||
|
#if DEBUG_VERSION
|
||||||
|
printf (" verdaux(%u): %s\n", vdef->vd_ndx, version);
|
||||||
|
#endif
|
||||||
|
verdaux = (ElfW(Verdaux) *) (((char *) verdaux) + verdaux->vda_next);
|
||||||
|
}
|
||||||
|
next = vdef->vd_next;
|
||||||
|
vdef = (ElfW(Verdef) *) (((char *) vdef) + next);
|
||||||
|
} while (next);
|
||||||
|
}
|
||||||
|
if (versym && verneed) {
|
||||||
|
vneed = verneed;
|
||||||
|
do {
|
||||||
|
ElfW(Vernaux) *vernaux =
|
||||||
|
(ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux);
|
||||||
|
|
||||||
|
lib = (char *) dynstr + vneed->vn_file;
|
||||||
|
#if DEBUG_VERSION
|
||||||
|
printf ("verneed: %u %s\n", vneed->vn_version, lib);
|
||||||
|
#endif
|
||||||
|
for (i = 0; i < vneed->vn_cnt; i++) {
|
||||||
|
if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */
|
||||||
|
version = (char *) dynstr + vernaux->vna_name;
|
||||||
|
save_def_need_index (&n_def_need, &def_need,
|
||||||
|
vernaux->vna_other, lib, version);
|
||||||
|
#if DEBUG_VERSION
|
||||||
|
printf (" vernaux(%u): %u %u %s\n",
|
||||||
|
vernaux->vna_other, vernaux->vna_hash,
|
||||||
|
vernaux->vna_flags, version);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next);
|
||||||
|
}
|
||||||
|
next = vneed->vn_next;
|
||||||
|
vneed = (ElfW(Verneed) *) (((char *) vneed) + next);
|
||||||
|
} while (next);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DEBUG_VERSION
|
||||||
|
for (i = 0; i < n_def_need; i++) {
|
||||||
|
if (def_need[i].lib) {
|
||||||
|
printf ("%d: lib: %s, version %s\n",
|
||||||
|
i, def_need[i].lib, def_need[i].version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* add the dll and its level */
|
/* add the dll and its level */
|
||||||
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
|
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
|
||||||
dllref->level = level;
|
dllref->level = level;
|
||||||
@ -2819,13 +3174,18 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
|
dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
|
||||||
|
|
||||||
/* add dynamic symbols in dynsym_section */
|
/* add dynamic symbols in dynsym_section */
|
||||||
for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
|
for(i = 1, sym = dynsym + 1, vsym = versym + 1; i < nb_syms; i++, sym++, vsym++) {
|
||||||
sym_bind = ELFW(ST_BIND)(sym->st_info);
|
sym_bind = ELFW(ST_BIND)(sym->st_info);
|
||||||
if (sym_bind == STB_LOCAL)
|
if (sym_bind == STB_LOCAL)
|
||||||
continue;
|
continue;
|
||||||
name = (char *) dynstr + sym->st_name;
|
name = (char *) dynstr + sym->st_name;
|
||||||
set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
|
sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
|
||||||
sym->st_info, sym->st_other, sym->st_shndx, name);
|
sym->st_info, sym->st_other, sym->st_shndx, name);
|
||||||
|
if (versym && n_def_need && (*vsym & 0x8000) == 0 &&
|
||||||
|
*vsym > 0 && *vsym < n_def_need &&
|
||||||
|
def_need[*vsym].lib) {
|
||||||
|
add_version_sym (s1->dynsymtab_section, sym_index, n_def_need, def_need, name, *vsym);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load all referenced DLLs */
|
/* load all referenced DLLs */
|
||||||
@ -2849,9 +3209,13 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
|||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
the_end:
|
the_end:
|
||||||
|
free_def_need (n_def_need, def_need);
|
||||||
tcc_free(dynstr);
|
tcc_free(dynstr);
|
||||||
tcc_free(dynsym);
|
tcc_free(dynsym);
|
||||||
tcc_free(dynamic);
|
tcc_free(dynamic);
|
||||||
|
tcc_free(verdef);
|
||||||
|
tcc_free(verneed);
|
||||||
|
tcc_free(versym);
|
||||||
tcc_free(shdr);
|
tcc_free(shdr);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user