- /* 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) {
-
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;
-
}
-
}
-
soname通常和文件名一样,但是如果不一样,内部解决依赖会以内部名字为主
比如把libm复制到当前目录, export LD_LIBRARY_PATH=.
mv libm.so.6 liba.so
xcm@u32:~/study/tinycc$ tcc t.c -L. -la
xcm@u32:~/study/tinycc$ ldd a.out
linux-gate.so.1 => (0xb77c6000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb778c000) 仍然找libm.so.6,因为liba的soname是它
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7632000)
/lib/ld-linux.so.2 (0xb77c7000)
xcm@u32:~/study/tinycc$ mv liba.so libm.so
xcm@u32:~/study/tinycc$ ldd a.out
linux-gate.so.1 => (0xb78a4000)
libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0xb786a000) 同样
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7710000)
/lib/ld-linux.so.2 (0xb78a5000)
xcm@u32:~/study/tinycc$ mv libm.so libm.so.6
xcm@u32:~/study/tinycc$ ldd a.out
linux-gate.so.1 => (0xb7757000)
libm.so.6 => ./libm.so.6 (0xb772f000) 这个时候就对了
libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb75c3000)
/lib/ld-linux.so.2 (0xb7758000)
-
/* 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 = 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;
-
}
-
}
-
-
// printf("loading dll '%s'\n", soname);
-
-
/* 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 = dynstr + sym->st_name;
- ok, 该符号可用了
-
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 = 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) {
-
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;
-
}