📄 elf.c
字号:
hash = elf_hash(name);
def = symlook_default(name, hash, refobj, &defobj, in_plt);
} else {
def = ref;
defobj = refobj;
}
/*
* If we found no definition and the reference is weak, treat the
* symbol as having the value zero.
*/
if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) {
def = &sym_zero;
defobj = obj_main;
}
if (def != NULL) {
*defobj_out = defobj;
/* Record the information in the cache to avoid subsequent lookups. */
if (cache != NULL) {
cache[symnum].sym = def;
cache[symnum].obj = defobj;
}
} else {
if (refobj != &obj_rtld)
_rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name);
}
return def;
}
#if 0
/*
* Return the search path from the ldconfig hints file, reading it if
* necessary. Returns NULL if there are problems with the hints file,
* or if the search path there is empty.
*/
static const char *
gethints(void)
{
static char *hints;
if (hints == NULL) {
int fd;
struct elfhints_hdr hdr;
char *p;
/* Keep from trying again in case the hints file is bad. */
hints = "";
if ((fd = open(_PATH_ELF_HINTS, O_RDONLY)) == -1)
return NULL;
if (read(fd, &hdr, sizeof hdr) != sizeof hdr ||
hdr.magic != ELFHINTS_MAGIC ||
hdr.version != 1) {
close(fd);
return NULL;
}
p = xmalloc(hdr.dirlistlen + 1);
if (lseek(fd, hdr.strtab + hdr.dirlist, SEEK_SET) == -1 ||
read(fd, p, hdr.dirlistlen + 1) != (ssize_t)hdr.dirlistlen + 1) {
free(p);
close(fd);
return NULL;
}
hints = p;
close(fd);
}
return hints[0] != '\0' ? hints : NULL;
}
static void
init_dag(Obj_Entry *root)
{
DoneList donelist;
donelist_init(&donelist);
init_dag1(root, root, &donelist);
}
static void
init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
{
const Needed_Entry *needed;
if (donelist_check(dlp, obj))
return;
obj->refcount++;
objlist_push_tail(&obj->dldags, root);
objlist_push_tail(&root->dagmembers, obj);
for (needed = obj->needed; needed != NULL; needed = needed->next)
if (needed->obj != NULL)
init_dag1(root, needed->obj, dlp);
}
/*
* Initialize the dynamic linker. The argument is the address at which
* the dynamic linker has been mapped into memory. The primary task of
* this function is to relocate the dynamic linker.
*/
static void
init_rtld(caddr_t mapbase)
{
Obj_Entry objtmp; /* Temporary rtld object */
/*
* Conjure up an Obj_Entry structure for the dynamic linker.
*
* The "path" member can't be initialized yet because string constatns
* cannot yet be acessed. Below we will set it correctly.
*/
memset(&objtmp, 0, sizeof(objtmp));
objtmp.path = NULL;
objtmp.rtld = true;
objtmp.mapbase = mapbase;
#ifdef PIC
objtmp.relocbase = mapbase;
#endif
if (RTLD_IS_DYNAMIC()) {
objtmp.dynamic = rtld_dynamic(&objtmp);
digest_dynamic(&objtmp, 1);
assert(objtmp.needed == NULL);
assert(!objtmp.textrel);
/*
* Temporarily put the dynamic linker entry into the object list, so
* that symbols can be found.
*/
relocate_objects(&objtmp, true, &objtmp);
}
/* Initialize the object list. */
obj_tail = &obj_list;
/* Now that non-local variables can be accesses, copy out obj_rtld. */
memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld));
/* Replace the path with a dynamically allocated copy. */
obj_rtld.path = xstrdup(PATH_RTLD);
r_debug.r_brk = r_debug_state;
r_debug.r_state = RT_CONSISTENT;
}
/*
* Add the init functions from a needed object list (and its recursive
* needed objects) to "list". This is not used directly; it is a helper
* function for initlist_add_objects(). The write lock must be held
* when this function is called.
*/
static void
initlist_add_neededs(Needed_Entry *needed, Objlist *list)
{
/* Recursively process the successor needed objects. */
if (needed->next != NULL)
initlist_add_neededs(needed->next, list);
/* Process the current needed object. */
if (needed->obj != NULL)
initlist_add_objects(needed->obj, &needed->obj->next, list);
}
/*
* Scan all of the DAGs rooted in the range of objects from "obj" to
* "tail" and add their init functions to "list". This recurses over
* the DAGs and ensure the proper init ordering such that each object's
* needed libraries are initialized before the object itself. At the
* same time, this function adds the objects to the global finalization
* list "list_fini" in the opposite order. The write lock must be
* held when this function is called.
*/
static void
initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list)
{
if (obj->init_done)
return;
obj->init_done = true;
/* Recursively process the successor objects. */
if (&obj->next != tail)
initlist_add_objects(obj->next, tail, list);
/* Recursively process the needed objects. */
if (obj->needed != NULL)
initlist_add_neededs(obj->needed, list);
/* Add the object to the init list. */
if (obj->init != (Elf_Addr)NULL)
objlist_push_tail(list, obj);
/* Add the object to the global fini list in the reverse order. */
if (obj->fini != (Elf_Addr)NULL)
objlist_push_head(&list_fini, obj);
}
#ifndef FPTR_TARGET
#define FPTR_TARGET(f) ((Elf_Addr) (f))
#endif
static bool
is_exported(const Elf_Sym *def)
{
Elf_Addr value;
const func_ptr_type *p;
value = (Elf_Addr)(obj_rtld.relocbase + def->st_value);
for (p = exports; *p != NULL; p++)
if (FPTR_TARGET(*p) == value)
return true;
return false;
}
/*
* Given a shared object, traverse its list of needed objects, and load
* each of them. Returns 0 on success. Generates an error message and
* returns -1 on failure.
*/
static int
load_needed_objects(Obj_Entry *first)
{
Obj_Entry *obj;
for (obj = first; obj != NULL; obj = obj->next) {
Needed_Entry *needed;
for (needed = obj->needed; needed != NULL; needed = needed->next) {
const char *name = obj->strtab + needed->name;
char *path = find_library(name, obj);
needed->obj = NULL;
if (path == NULL && !ld_tracing)
return -1;
if (path) {
needed->obj = load_object(path);
if (needed->obj == NULL && !ld_tracing)
return -1; /* XXX - cleanup */
}
}
}
return 0;
}
static int
load_preload_objects(void)
{
char *p = ld_preload;
static const char delim[] = " \t:;";
if (p == NULL)
return 0;
p += strspn(p, delim);
while (*p != '\0') {
size_t len = strcspn(p, delim);
char *path;
char savech;
savech = p[len];
p[len] = '\0';
if ((path = find_library(p, NULL)) == NULL)
return -1;
if (load_object(path) == NULL)
return -1; /* XXX - cleanup */
p[len] = savech;
p += len;
p += strspn(p, delim);
}
return 0;
}
/*
* Load a shared object into memory, if it is not already loaded. The
* argument must be a string allocated on the heap. This function assumes
* responsibility for freeing it when necessary.
*
* Returns a pointer to the Obj_Entry for the object. Returns NULL
* on failure.
*/
static Obj_Entry *
load_object(char *path)
{
Obj_Entry *obj;
int fd = -1;
struct stat sb;
for (obj = obj_list->next; obj != NULL; obj = obj->next)
if (strcmp(obj->path, path) == 0)
break;
/*
* If we didn't find a match by pathname, open the file and check
* again by device and inode. This avoids false mismatches caused
* by multiple links or ".." in pathnames.
*
* To avoid a race, we open the file and use fstat() rather than
* using stat().
*/
if (obj == NULL) {
if ((fd = open(path, O_RDONLY)) == -1) {
_rtld_error("Cannot open \"%s\"", path);
return NULL;
}
if (fstat(fd, &sb) == -1) {
_rtld_error("Cannot fstat \"%s\"", path);
close(fd);
return NULL;
}
for (obj = obj_list->next; obj != NULL; obj = obj->next) {
if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) {
close(fd);
break;
}
}
}
if (obj == NULL) { /* First use of this object, so we must map it in */
dbg("loading \"%s\"", path);
obj = map_object(fd, path, &sb);
close(fd);
if (obj == NULL) {
free(path);
return NULL;
}
obj->path = path;
digest_dynamic(obj, 0);
*obj_tail = obj;
obj_tail = &obj->next;
obj_count++;
linkmap_add(obj); /* for GDB & dlinfo() */
dbg(" %p .. %p: %s", obj->mapbase,
obj->mapbase + obj->mapsize - 1, obj->path);
if (obj->textrel)
dbg(" WARNING: %s has impure text", obj->path);
} else
free(path);
return obj;
}
static Obj_Entry *
obj_from_addr(const void *addr)
{
Obj_Entry *obj;
for (obj = obj_list; obj != NULL; obj = obj->next) {
if (addr < (void *) obj->mapbase)
continue;
if (addr < (void *) (obj->mapbase + obj->mapsize))
return obj;
}
return NULL;
}
/*
* Call the finalization functions for each of the objects in "list"
* which are unreferenced. All of the objects are expected to have
* non-NULL fini functions.
*/
static void
objlist_call_fini(Objlist *list)
{
Objlist_Entry *elm;
char *saved_msg;
/*
* Preserve the current error message since a fini function might
* call into the dynamic linker and overwrite it.
*/
saved_msg = errmsg_save();
STAILQ_FOREACH(elm, list, link) {
if (elm->obj->refcount == 0) {
dbg("calling fini function for %s at %p", elm->obj->path,
(void *)elm->obj->fini);
call_initfini_pointer(elm->obj, elm->obj->fini);
}
}
errmsg_restore(saved_msg);
}
/*
* Call the initialization functions for each of the objects in
* "list". All of the objects are expected to have non-NULL init
* functions.
*/
static void
objlist_call_init(Objlist *list)
{
Objlist_Entry *elm;
char *saved_msg;
/*
* Preserve the current error message since an init function might
* call into the dynamic linker and overwrite it.
*/
saved_msg = errmsg_save();
STAILQ_FOREACH(elm, list, link) {
dbg("calling init function for %s at %p", elm->obj->path,
(void *)elm->obj->init);
call_initfini_pointer(elm->obj, elm->obj->init);
}
errmsg_restore(saved_msg);
}
static void
objlist_clear(Objlist *list)
{
Objlist_Entry *elm;
while (!STAILQ_EMPTY(list)) {
elm = STAILQ_FIRST(list);
STAILQ_REMOVE_HEAD(list, link);
free(elm);
}
}
static Objlist_Entry *
objlist_find(Objlist *list, const Obj_Entry *obj)
{
Objlist_Entry *elm;
STAILQ_FOREACH(elm, list, link)
if (elm->obj == obj)
return elm;
return NULL;
}
static void
objlist_init(Objlist *list)
{
STAILQ_INIT(list);
}
static void
objlist_push_head(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
elm = NEW(Objlist_Entry);
elm->obj = obj;
STAILQ_INSERT_HEAD(list, elm, link);
}
static void
objlist_push_tail(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
elm = NEW(Objlist_Entry);
elm->obj = obj;
STAILQ_INSERT_TAIL(list, elm, link);
}
static void
objlist_remove(Objlist *list, Obj_Entry *obj)
{
Objlist_Entry *elm;
if ((elm = objlist_find(list, obj)) != NULL) {
STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link);
free(elm);
}
}
/*
* Remove all of the unreferenced objects from "list".
*/
static void
objlist_remove_unref(Objlist *list)
{
Objlist newlist;
Objlist_Entry *elm;
STAILQ_INIT(&newlist);
while (!STAILQ_EMPTY(list)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -