/* * We call this function when we have just read an ELF library or executable. * We add the relevant info to the symbol chain, so that we can resolve all * externals properly. */ struct elf_resolve *_dl_add_elf_hash_table(const char *libname, DL_LOADADDR_TYPE loadaddr, unsigned long *dynamic_info, unsigned long dynamic_addr, attribute_unused unsigned long dynamic_size) { Elf_Symndx *hash_addr; struct elf_resolve *tpnt; int i; tpnt = _dl_malloc(sizeof(struct elf_resolve)); _dl_memset(tpnt, 0, sizeof(struct elf_resolve)); if (!_dl_loaded_modules) _dl_loaded_modules = tpnt; else { struct elf_resolve *t = _dl_loaded_modules; while (t->next) t = t->next; t->next = tpnt; t->next->prev = t; tpnt = t->next; } tpnt->next = NULL; tpnt->init_flag = 0; tpnt->libname = _dl_strdup(libname); tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr; tpnt->libtype = loaded_file; #ifdef __DSBT__ if (dynamic_info[DT_DSBT_BASE_IDX] != 0) tpnt->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX]; if (dynamic_info[DT_DSBT_SIZE_IDX] != 0) tpnt->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX]; if (dynamic_info[DT_DSBT_INDEX_IDX] != 0) tpnt->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX]; #endif /* __DSBT__ */ #ifdef __LDSO_GNU_HASH_SUPPORT__ if (dynamic_info[DT_GNU_HASH_IDX] != 0) { Elf32_Word *hash32 = (Elf_Symndx*)dynamic_info[DT_GNU_HASH_IDX]; tpnt->nbucket = *hash32++; Elf32_Word symbias = *hash32++; Elf32_Word bitmask_nwords = *hash32++; /* Must be a power of two. */ _dl_assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0); tpnt->l_gnu_bitmask_idxbits = bitmask_nwords - 1; tpnt->l_gnu_shift = *hash32++; tpnt->l_gnu_bitmask = (ElfW(Addr) *) hash32; hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords; tpnt->l_gnu_buckets = hash32; hash32 += tpnt->nbucket; tpnt->l_gnu_chain_zero = hash32 - symbias; } else
/* * Initialize a new dynamic object. */ elf_object_t * _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, int phdrc, const int objtype, const long lbase, const long obase) { elf_object_t *object; #if 0 _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", objname, dynp, objtype, lbase, obase); #endif object = _dl_calloc(1, sizeof(elf_object_t)); if (object == NULL) _dl_exit(7); object->prev = object->next = NULL; object->load_dyn = dynp; while (dynp->d_tag != DT_NULL) { if (dynp->d_tag < DT_NUM) object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val; else if (dynp->d_tag >= DT_LOPROC && dynp->d_tag < DT_LOPROC + DT_PROCNUM) object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = dynp->d_un.d_val; if (dynp->d_tag == DT_TEXTREL) object->dyn.textrel = 1; if (dynp->d_tag == DT_SYMBOLIC) object->dyn.symbolic = 1; if (dynp->d_tag == DT_BIND_NOW) object->obj_flags |= DF_1_NOW; if (dynp->d_tag == DT_FLAGS_1) object->obj_flags |= dynp->d_un.d_val; if (dynp->d_tag == DT_RELACOUNT) object->relacount = dynp->d_un.d_val; if (dynp->d_tag == DT_RELCOUNT) object->relcount = dynp->d_un.d_val; dynp++; } DL_DEB((" flags %s = 0x%x\n", objname, object->obj_flags )); object->obj_type = objtype; if (_dl_loading_object == NULL) { /* * no loading object, object is the loading object, * as it is either executable, or dlopened() */ _dl_loading_object = object; } if ((object->obj_flags & DF_1_NOOPEN) != 0 && _dl_loading_object->obj_type == OBJTYPE_DLO && _dl_traceld == NULL) { _dl_free(object); _dl_errno = DL_CANT_LOAD_OBJ; return(NULL); } /* * Now relocate all pointer to dynamic info, but only * the ones which have pointer values. */ if (object->Dyn.info[DT_PLTGOT]) object->Dyn.info[DT_PLTGOT] += obase; if (object->Dyn.info[DT_HASH]) object->Dyn.info[DT_HASH] += obase; if (object->Dyn.info[DT_STRTAB]) object->Dyn.info[DT_STRTAB] += obase; if (object->Dyn.info[DT_SYMTAB]) object->Dyn.info[DT_SYMTAB] += obase; if (object->Dyn.info[DT_RELA]) object->Dyn.info[DT_RELA] += obase; if (object->Dyn.info[DT_SONAME]) object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB]; if (object->Dyn.info[DT_RPATH]) object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB]; if (object->Dyn.info[DT_REL]) object->Dyn.info[DT_REL] += obase; if (object->Dyn.info[DT_INIT]) object->Dyn.info[DT_INIT] += obase; if (object->Dyn.info[DT_FINI]) object->Dyn.info[DT_FINI] += obase; if (object->Dyn.info[DT_JMPREL]) object->Dyn.info[DT_JMPREL] += obase; if (object->Dyn.info[DT_HASH] != 0) { Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH]; object->nbuckets = hashtab[0]; object->nchains = hashtab[1]; object->buckets = hashtab + 2; object->chains = object->buckets + object->nbuckets; } object->phdrp = phdrp; object->phdrc = phdrc; object->load_base = lbase; object->obj_base = obase; object->load_name = _dl_strdup(objname); if (object->load_name == NULL) _dl_exit(7); object->load_object = _dl_loading_object; if (object->load_object == object) DL_DEB(("head %s\n", object->load_name)); DL_DEB(("obj %s has %s as head\n", object->load_name, _dl_loading_object->load_name )); object->refcount = 0; TAILQ_INIT(&object->child_list); object->opencount = 0; /* # dlopen() & exe */ object->grprefcount = 0; /* default dev, inode for dlopen-able objects. */ object->dev = 0; object->inode = 0; object->grpsym_gen = 0; TAILQ_INIT(&object->grpsym_list); TAILQ_INIT(&object->grpref_list); if (object->dyn.rpath) { object->rpath = _dl_split_path(object->dyn.rpath); if ((object->obj_flags & DF_1_ORIGIN) && _dl_trust) _dl_origin_subst(object); } _dl_trace_object_setup(object); return (object); }
/* * Initialize a new dynamic object. */ elf_object_t * _dl_finalize_object(const char *objname, Elf_Dyn *dynp, Elf_Phdr *phdrp, int phdrc, const int objtype, const long lbase, const long obase) { elf_object_t *object; #if 0 _dl_printf("objname [%s], dynp %p, objtype %x lbase %lx, obase %lx\n", objname, dynp, objtype, lbase, obase); #endif object = _dl_malloc(sizeof(elf_object_t)); object->prev = object->next = NULL; object->load_dyn = dynp; while (dynp->d_tag != DT_NULL) { if (dynp->d_tag < DT_NUM) object->Dyn.info[dynp->d_tag] = dynp->d_un.d_val; else if (dynp->d_tag >= DT_LOPROC && dynp->d_tag < DT_LOPROC + DT_PROCNUM) object->Dyn.info[dynp->d_tag + DT_NUM - DT_LOPROC] = dynp->d_un.d_val; if (dynp->d_tag == DT_TEXTREL) object->dyn.textrel = 1; if (dynp->d_tag == DT_SYMBOLIC) object->dyn.symbolic = 1; if (dynp->d_tag == DT_BIND_NOW) object->obj_flags = RTLD_NOW; dynp++; } /* * Now relocate all pointer to dynamic info, but only * the ones which have pointer values. */ if (object->Dyn.info[DT_PLTGOT]) object->Dyn.info[DT_PLTGOT] += obase; if (object->Dyn.info[DT_HASH]) object->Dyn.info[DT_HASH] += obase; if (object->Dyn.info[DT_STRTAB]) object->Dyn.info[DT_STRTAB] += obase; if (object->Dyn.info[DT_SYMTAB]) object->Dyn.info[DT_SYMTAB] += obase; if (object->Dyn.info[DT_RELA]) object->Dyn.info[DT_RELA] += obase; if (object->Dyn.info[DT_SONAME]) object->Dyn.info[DT_SONAME] += obase; if (object->Dyn.info[DT_RPATH]) object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB]; if (object->Dyn.info[DT_REL]) object->Dyn.info[DT_REL] += obase; if (object->Dyn.info[DT_INIT]) object->Dyn.info[DT_INIT] += obase; if (object->Dyn.info[DT_FINI]) object->Dyn.info[DT_FINI] += obase; if (object->Dyn.info[DT_JMPREL]) object->Dyn.info[DT_JMPREL] += obase; if (object->Dyn.info[DT_HASH] != 0) { Elf_Word *hashtab = (Elf_Word *)object->Dyn.info[DT_HASH]; object->nbuckets = hashtab[0]; object->nchains = hashtab[1]; object->buckets = hashtab + 2; object->chains = object->buckets + object->nbuckets; } object->phdrp = phdrp; object->phdrc = phdrc; object->obj_type = objtype; object->load_base = lbase; object->obj_base = obase; object->load_name = _dl_strdup(objname); if (_dl_loading_object == NULL) { /* * no loading object, object is the loading object, * as it is either executable, or dlopened() */ _dl_loading_object = object->load_object = object; DL_DEB(("head %s\n", object->load_name )); } else { object->load_object = _dl_loading_object; } DL_DEB(("obj %s has %s as head\n", object->load_name, _dl_loading_object->load_name )); object->refcount = 0; TAILQ_INIT(&object->child_list); object->opencount = 0; /* # dlopen() & exe */ object->grprefcount = 0; /* default dev, inode for dlopen-able objects. */ object->dev = 0; object->inode = 0; TAILQ_INIT(&object->grpsym_list); TAILQ_INIT(&object->grpref_list); return(object); }
/* * Perform $ORIGIN substitutions on path */ static void _dl_origin_subst_path(elf_object_t *object, const char *origin_path, char **path) { char tmp_path[PATH_MAX]; char *new_path, *tp; const char *pp, *name, *value; static struct utsname uts; size_t value_len; int skip_brace; if (uts.sysname[0] == '\0') { if (_dl_uname(&uts) != 0) return; } tp = tmp_path; pp = *path; while (*pp != '\0' && (tp - tmp_path) < sizeof(tmp_path)) { /* copy over chars up to but not including $ */ while (*pp != '\0' && *pp != '$' && (tp - tmp_path) < sizeof(tmp_path)) *tp++ = *pp++; /* substitution sequence detected */ if (*pp == '$' && (tp - tmp_path) < sizeof(tmp_path)) { pp++; if ((skip_brace = (*pp == '{'))) pp++; /* skip over name */ name = pp; while (_dl_isalnum((unsigned char)*pp) || *pp == '_') pp++; switch (_dl_subst_name(name, pp - name)) { case SUBST_ORIGIN: value = origin_path; break; case SUBST_OSNAME: value = uts.sysname; break; case SUBST_OSREL: value = uts.release; break; case SUBST_PLATFORM: value = uts.machine; break; default: value = ""; } value_len = _dl_strlen(value); if (value_len >= sizeof(tmp_path) - (tp - tmp_path)) return; _dl_bcopy(value, tp, value_len); tp += value_len; if (skip_brace && *pp == '}') pp++; } } /* no substitution made if result exceeds sizeof(tmp_path) */ if (tp - tmp_path >= sizeof(tmp_path)) return; /* NULL terminate tmp_path */ *tp = '\0'; if (_dl_strcmp(tmp_path, *path) == 0) return; new_path = _dl_strdup(tmp_path); if (new_path == NULL) return; DL_DEB(("orig_path %s\n", *path)); DL_DEB(("new_path %s\n", new_path)); _dl_free(*path); *path = new_path; }