BOOL DLSYM_canonical_lookup(DLOAD_HANDLE handle, int sym_index, DLIMP_Dynamic_Module *dyn_module, Elf32_Addr *sym_value) { /*------------------------------------------------------------------------*/ /* Lookup the symbol table to get the symbol characteristics. */ /*------------------------------------------------------------------------*/ struct Elf32_Sym *sym = &dyn_module->symtab[sym_index]; int32_t st_bind = ELF32_ST_BIND(sym->st_info); int32_t st_vis = ELF32_ST_VISIBILITY(sym->st_other); BOOL is_def = (sym->st_shndx != SHN_UNDEF && (sym->st_shndx < SHN_LORESERVE || sym->st_shndx == SHN_ABS || sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_XINDEX)); const char *sym_name = (char *)sym->st_name; #if LOADER_DEBUG if (debugging_on) DLIF_trace("DLSYM_canonical_lookup: %d, %s\n", sym_index, sym_name); #endif /*------------------------------------------------------------------------*/ /* Local symbols and symbol definitions that cannot be pre-empted */ /* are resolved by the definition in the same module. */ /*------------------------------------------------------------------------*/ if (st_bind == STB_LOCAL || st_vis != STV_DEFAULT) { /*---------------------------------------------------------------------*/ /* If it is a local symbol or non-local that cannot be preempted, */ /* the definition should be found in the same module. If we don't */ /* find the definition it is an error. */ /*---------------------------------------------------------------------*/ if (!is_def) { DLIF_error(DLET_SYMBOL, "Local/non-imported symbol %s definition is not found " "in module %s!\n", sym_name, dyn_module->name); return FALSE; } else { if (sym_value) *sym_value = sym->st_value; return TRUE; } } /*------------------------------------------------------------------------*/ /* Else we have either pre-emptable defintion or undef symbol. We need */ /* to do global look up. */ /*------------------------------------------------------------------------*/ else { return DLSYM_global_lookup(handle, sym_name, dyn_module->loaded_module, sym_value); } }
static const char *get_st_visibility(unsigned char val) { static const char *const visibilities[] = { "DEFAULT", "INTERNAL", "HIDDEN", "PROTECTED" }; return visibilities[ELF32_ST_VISIBILITY(val)]; }
static int do_test (void) { void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY); if (handle == NULL) printf ("nonexistent: %s\n", dlerror ()); else exit (1); handle = dlopen ("modstatic2.so", RTLD_LAZY); if (handle == NULL) { printf ("%s\n", dlerror ()); exit (1); } int (*test) (FILE *, int); test = dlsym (handle, "test"); if (test == NULL) { printf ("%s\n", dlerror ()); exit (1); } Dl_info info; int res = dladdr (test, &info); if (res == 0) { puts ("dladdr returned 0"); exit (1); } else { if (strstr (info.dli_fname, "modstatic2.so") == NULL || strcmp (info.dli_sname, "test") != 0) { printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname); exit (1); } if (info.dli_saddr != (void *) test) { printf ("saddr %p != test %p\n", info.dli_saddr, test); exit (1); } } ElfW(Sym) *sym; void *symp; res = dladdr1 (test, &info, &symp, RTLD_DL_SYMENT); if (res == 0) { puts ("dladdr1 returned 0"); exit (1); } else { if (strstr (info.dli_fname, "modstatic2.so") == NULL || strcmp (info.dli_sname, "test") != 0) { printf ("fname %s sname %s\n", info.dli_fname, info.dli_sname); exit (1); } if (info.dli_saddr != (void *) test) { printf ("saddr %p != test %p\n", info.dli_saddr, test); exit (1); } sym = symp; if (sym == NULL) { puts ("sym == NULL\n"); exit (1); } if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT) { printf ("bind %d visibility %d\n", (int) ELF32_ST_BIND (sym->st_info), (int) ELF32_ST_VISIBILITY (sym->st_other)); exit (1); } } Lmid_t lmid; res = dlinfo (handle, RTLD_DI_LMID, &lmid); if (res != 0) { printf ("dlinfo returned %d %s\n", res, dlerror ()); exit (1); } else if (lmid != LM_ID_BASE) { printf ("lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE); exit (1); } res = test (stdout, 2); if (res != 4) { printf ("Got %i, expected 4\n", res); exit (1); } void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY); if (handle2 == NULL) { printf ("libdl.so: %s\n", dlerror ()); exit (1); } if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL) { printf ("dlvsym: %s\n", dlerror ()); exit (1); } void *(*dlsymfn) (void *, const char *); dlsymfn = dlsym (handle2, "dlsym"); if (dlsymfn == NULL) { printf ("dlsym \"dlsym\": %s\n", dlerror ()); exit (1); } void *test2 = dlsymfn (handle, "test"); if (test2 == NULL) { printf ("%s\n", dlerror ()); exit (1); } else if (test2 != (void *) test) { printf ("test %p != test2 %p\n", test, test2); exit (1); } dlclose (handle2); dlclose (handle); handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY); if (handle == NULL) { printf ("%s\n", dlerror ()); exit (1); } dlclose (handle); handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY); if (handle == NULL) printf ("LM_ID_NEWLM: %s\n", dlerror ()); else { puts ("LM_ID_NEWLM unexpectedly succeeded"); exit (1); } return 0; }
Elf_Scn *symtab_write_elf(Elf *e, struct sect * sects, struct buffer *strtab_buf, struct buffer *shstrtab_buf) { unsigned i, k; struct sym_info *sym; Elf32_Sym esym; Elf_Scn *scn, *relscn, *tmpscn; Elf_Data *data, *reldata; Elf32_Shdr *shdr, *relshdr; struct buffer buf; struct buffer *relbuf; struct sect *s; buffer_init(&buf); esym.st_name = 0; esym.st_value = 0; esym.st_size = 0; esym.st_info = 0; esym.st_other = 0; esym.st_shndx = 0; buffer_writemem(&buf, &esym, sizeof(esym)); relbuf = malloc(0); for (s = sects, k = 0; s != NULL; s = s->next, k++) { relbuf = realloc(relbuf, (k+1)*sizeof(struct buffer)); buffer_init(&relbuf[k]); } for (i = 0; i < SYMTAB_SIZE; i++) { for (sym = symtab[i]; sym != NULL; sym = sym->next) { if (sym->symbol[0] != '.' || sym->relocs != NULL) { struct reloc_info size; int type = STT_NOTYPE; int bind = STB_LOCAL; if (!sym->defined || sym->bind == SYM_BIND_GLOBAL) { bind = STB_GLOBAL; } esym.st_name = strtab_buf->pos; buffer_writestr(strtab_buf, sym->symbol); esym.st_value = sym->addr; size = expr_evaluate(sym->size); if (size.symbol != NULL) { eprintf("Cannot relocate symbol size"); exit(EXIT_FAILURE); } esym.st_size = size.intval; if (strcmp(sym->type, "@function") == 0) type = STT_FUNC; if (strcmp(sym->type, "@object") == 0) type = STT_OBJECT; esym.st_info = ELF32_ST_INFO(bind, type); esym.st_other = ELF32_ST_VISIBILITY(STV_DEFAULT); tmpscn = section_find(e, sym->section, shstrtab_buf); if (tmpscn == NULL && sym->section != NULL) tmpscn = section_find(e, pile_name(pile_match(sym->section)), shstrtab_buf); esym.st_shndx = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; if (sym->relocs != NULL) { struct sym_reloc_info *r; for (r = sym->relocs; r != NULL; r = r->next) { Elf32_Rela rel; rel.r_offset = r->addr; rel.r_info = ELF32_R_INFO(buf.pos/sizeof(esym), r->type); rel.r_addend = r->addend; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (strcmp(s->name, r->sect) == 0) { buffer_writemem(&relbuf[k], &rel, sizeof(rel)); } } } } buffer_writemem(&buf, &esym, sizeof(esym)); } } } scn = xelf_newscn(e); shdr = xelf32_getshdr(scn); shdr->sh_name = shstrtab_buf->pos; buffer_writestr(shstrtab_buf, ".symtab"); shdr->sh_type = SHT_SYMTAB; shdr->sh_flags = 0; data = xelf_newdata(scn); data->d_align = 4; data->d_off = 0; data->d_type = ELF_T_SYM; data->d_version = EV_CURRENT; data->d_buf = buf.data; data->d_size = buf.pos; for (s = sects, k = 0; s != NULL; s = s->next, k++) { if (relbuf[k].pos > 0) { char *relname; relscn = xelf_newscn(e); relshdr = xelf32_getshdr(relscn); relshdr->sh_name = shstrtab_buf->pos; relname = malloc(strlen(s->name)+6); strcpy(relname, ".rela"); strcat(relname, s->name); buffer_writestr(shstrtab_buf, relname); relshdr->sh_type = SHT_RELA; shdr->sh_flags = 0; reldata = xelf_newdata(relscn); reldata->d_align = 4; reldata->d_off = 0; reldata->d_type = ELF_T_RELA; reldata->d_version = EV_CURRENT; reldata->d_buf = relbuf[k].data; reldata->d_size = relbuf[k].pos; relshdr->sh_link = elf_ndxscn(scn); tmpscn = section_find(e, s->name, shstrtab_buf); relshdr->sh_info = tmpscn != NULL ? elf_ndxscn(tmpscn) : 0; } } return scn; }
int test (FILE *out, int a) { fputs ("in modstatic2.c (test)\n", out); void *handle = dlopen ("modstatic2-nonexistent.so", RTLD_LAZY); if (handle == NULL) fprintf (out, "nonexistent: %s\n", dlerror ()); else exit (1); handle = dlopen ("modstatic2.so", RTLD_LAZY); if (handle == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } int (*test2) (FILE *, int); test2 = dlsym (handle, "test"); if (test2 == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } if (test2 != test) { fprintf (out, "test %p != test2 %p\n", test, test2); exit (1); } Dl_info info; int res = dladdr (test2, &info); if (res == 0) { fputs ("dladdr returned 0\n", out); exit (1); } else { if (strstr (info.dli_fname, "modstatic2.so") == NULL || strcmp (info.dli_sname, "test") != 0) { fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname); exit (1); } if (info.dli_saddr != (void *) test2) { fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2); exit (1); } } ElfW(Sym) *sym; void *symp; res = dladdr1 (test2, &info, &symp, RTLD_DL_SYMENT); if (res == 0) { fputs ("dladdr1 returned 0\n", out); exit (1); } else { if (strstr (info.dli_fname, "modstatic2.so") == NULL || strcmp (info.dli_sname, "test") != 0) { fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname); exit (1); } if (info.dli_saddr != (void *) test2) { fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test2); exit (1); } sym = symp; if (sym == NULL) { fputs ("sym == NULL\n", out); exit (1); } if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT) { fprintf (out, "bind %d visibility %d\n", (int) ELF32_ST_BIND (sym->st_info), (int) ELF32_ST_VISIBILITY (sym->st_other)); exit (1); } } Lmid_t lmid; res = dlinfo (handle, RTLD_DI_LMID, &lmid); if (res != 0) { fprintf (out, "dlinfo returned %d %s\n", res, dlerror ()); exit (1); } else if (lmid != LM_ID_BASE) { fprintf (out, "lmid %d != %d\n", (int) lmid, (int) LM_ID_BASE); exit (1); } void *handle2 = dlopen (LIBDL_SO, RTLD_LAZY); if (handle2 == NULL) { fprintf (out, "libdl.so: %s\n", dlerror ()); exit (1); } #ifdef DO_VERSIONING if (dlvsym (handle2, "_dlfcn_hook", "GLIBC_PRIVATE") == NULL) { fprintf (out, "dlvsym: %s\n", dlerror ()); exit (1); } #endif void *(*dlsymfn) (void *, const char *); dlsymfn = dlsym (handle2, "dlsym"); if (dlsymfn == NULL) { fprintf (out, "dlsym \"dlsym\": %s\n", dlerror ()); exit (1); } void *test3 = dlsymfn (handle, "test"); if (test3 == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } else if (test3 != (void *) test2) { fprintf (out, "test2 %p != test3 %p\n", test2, test3); exit (1); } dlclose (handle2); dlclose (handle); handle = dlmopen (LM_ID_BASE, "modstatic2.so", RTLD_LAZY); if (handle == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } dlclose (handle); handle = dlmopen (LM_ID_NEWLM, "modstatic2.so", RTLD_LAZY); if (handle == NULL) fprintf (out, "LM_ID_NEWLM: %s\n", dlerror ()); else { fputs ("LM_ID_NEWLM unexpectedly succeeded\n", out); exit (1); } handle = dlopen ("modstatic.so", RTLD_LAZY); if (handle == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } int (*test4) (int); test4 = dlsym (handle, "test"); if (test4 == NULL) { fprintf (out, "%s\n", dlerror ()); exit (1); } res = test4 (16); if (res != 16 + 16) { fprintf (out, "modstatic.so (test) returned %d\n", res); exit (1); } res = dladdr1 (test4, &info, &symp, RTLD_DL_SYMENT); if (res == 0) { fputs ("dladdr1 returned 0\n", out); exit (1); } else { if (strstr (info.dli_fname, "modstatic.so") == NULL || strcmp (info.dli_sname, "test") != 0) { fprintf (out, "fname %s sname %s\n", info.dli_fname, info.dli_sname); exit (1); } if (info.dli_saddr != (void *) test4) { fprintf (out, "saddr %p != test %p\n", info.dli_saddr, test4); exit (1); } sym = symp; if (sym == NULL) { fputs ("sym == NULL\n", out); exit (1); } if (ELF32_ST_BIND (sym->st_info) != STB_GLOBAL || ELF32_ST_VISIBILITY (sym->st_other) != STV_DEFAULT) { fprintf (out, "bind %d visibility %d\n", (int) ELF32_ST_BIND (sym->st_info), (int) ELF32_ST_VISIBILITY (sym->st_other)); exit (1); } } dlclose (handle); fputs ("leaving modstatic2.c (test)\n", out); return a + a; }