⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 elf.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 5 页
字号:
	elm = STAILQ_FIRST(list);
	STAILQ_REMOVE_HEAD(list, link);
	if (elm->obj->refcount == 0)
	    free(elm);
	else
	    STAILQ_INSERT_TAIL(&newlist, elm, link);
    }
    *list = newlist;
}

#endif /* 0 */

/*
 * Relocate newly-loaded shared objects.  The argument is a pointer to
 * the Obj_Entry for the first such object.  All objects from the first
 * to the end of the list of objects are relocated.  Returns 0 on success,
 * or -1 on failure.
 */
static int
relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj)
{
    Obj_Entry *obj;

    for (obj = first;  obj != NULL;  obj = obj->next) {
	if (obj != rtldobj)
	    dbg("relocating \"%s\"", obj->path);
	if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL ||
	    obj->symtab == NULL || obj->strtab == NULL) {
	    _rtld_error("%s: Shared object has no run-time symbol table",
	      obj->path);
	    return -1;
	}

	if (obj->textrel) {
	    /* There are relocations to the write-protected text segment. */
	    if (mprotect(obj->mapbase, obj->textsize,
	      PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
		_rtld_error("%s: Cannot write-enable text segment: %s",
		  obj->path, strerror(errno));
		return -1;
	    }
	}

	/* Process the non-PLT relocations. */
	if (reloc_non_plt(obj, rtldobj))
		return -1;

	if (obj->textrel) {	/* Re-protected the text segment. */
	    if (mprotect(obj->mapbase, obj->textsize,
	      PROT_READ|PROT_EXEC) == -1) {
		_rtld_error("%s: Cannot write-protect text segment: %s",
		  obj->path, strerror(errno));
		return -1;
	    }
	}

	/* Process the PLT relocations. */
	if (reloc_plt(obj) == -1)
	    return -1;
	/* Relocate the jump slots if we are doing immediate binding. */
	if (obj->bind_now || bind_now)
	    if (reloc_jmpslots(obj) == -1)
		return -1;


	/*
	 * Set up the magic number and version in the Obj_Entry.  These
	 * were checked in the crt1.o from the original ElfKit, so we
	 * set them for backward compatibility.
	 */
	obj->magic = RTLD_MAGIC;
	obj->version = RTLD_VERSION;

	/* Set the special PLT or GOT entries. */
	init_pltgot(obj);
    }

    return 0;
}

#if 0

/*
 * Cleanup procedure.  It will be called (by the atexit mechanism) just
 * before the process exits.
 */
static void
rtld_exit(void)
{
    Obj_Entry *obj;

    dbg("rtld_exit()");
    /* Clear all the reference counts so the fini functions will be called. */
    for (obj = obj_list;  obj != NULL;  obj = obj->next)
	obj->refcount = 0;
    objlist_call_fini(&list_fini);
    /* No need to remove the items from the list, since we are exiting. */
    if (!libmap_disable)
        lm_fini();
}

static void *
path_enumerate(const char *path, path_enum_proc callback, void *arg)
{
#ifdef COMPAT_32BIT
    const char *trans;
#endif
    if (path == NULL)
	return (NULL);

    path += strspn(path, ":;");
    while (*path != '\0') {
	size_t len;
	char  *res;

	len = strcspn(path, ":;");
#ifdef COMPAT_32BIT
	trans = lm_findn(NULL, path, len);
	if (trans)
	    res = callback(trans, strlen(trans), arg);
	else
#endif
	res = callback(path, len, arg);

	if (res != NULL)
	    return (res);

	path += len;
	path += strspn(path, ":;");
    }

    return (NULL);
}

struct try_library_args {
    const char	*name;
    size_t	 namelen;
    char	*buffer;
    size_t	 buflen;
};

static void *
try_library_path(const char *dir, size_t dirlen, void *param)
{
    struct try_library_args *arg;

    arg = param;
    if (*dir == '/' || trust) {
	char *pathname;

	if (dirlen + 1 + arg->namelen + 1 > arg->buflen)
		return (NULL);

	pathname = arg->buffer;
	strncpy(pathname, dir, dirlen);
	pathname[dirlen] = '/';
	strcpy(pathname + dirlen + 1, arg->name);

	dbg("  Trying \"%s\"", pathname);
	if (access(pathname, F_OK) == 0) {		/* We found it */
	    pathname = xmalloc(dirlen + 1 + arg->namelen + 1);
	    strcpy(pathname, arg->buffer);
	    return (pathname);
	}
    }
    return (NULL);
}

static char *
search_library_path(const char *name, const char *path)
{
    char *p;
    struct try_library_args arg;

    if (path == NULL)
	return NULL;

    arg.name = name;
    arg.namelen = strlen(name);
    arg.buffer = xmalloc(PATH_MAX);
    arg.buflen = PATH_MAX;

    p = path_enumerate(path, try_library_path, &arg);

    free(arg.buffer);

    return (p);
}

int
dlclose(void *handle)
{
    Obj_Entry *root;
    int lockstate;

    lockstate = wlock_acquire(rtld_bind_lock);
    root = dlcheck(handle);
    if (root == NULL) {
	wlock_release(rtld_bind_lock, lockstate);
	return -1;
    }

    /* Unreference the object and its dependencies. */
    root->dl_refcount--;

    unref_dag(root);

    if (root->refcount == 0) {
	/*
	 * The object is no longer referenced, so we must unload it.
	 * First, call the fini functions with no locks held.
	 */
	wlock_release(rtld_bind_lock, lockstate);
	objlist_call_fini(&list_fini);
	lockstate = wlock_acquire(rtld_bind_lock);
	objlist_remove_unref(&list_fini);

	/* Finish cleaning up the newly-unreferenced objects. */
	GDB_STATE(RT_DELETE,&root->linkmap);
	unload_object(root);
	GDB_STATE(RT_CONSISTENT,NULL);
    }
    wlock_release(rtld_bind_lock, lockstate);
    return 0;
}

const char *
dlerror(void)
{
    char *msg = error_message;
    error_message = NULL;
    return msg;
}

/*
 * This function is deprecated and has no effect.
 */
void
dllockinit(void *context,
	   void *(*lock_create)(void *context),
           void (*rlock_acquire)(void *lock),
           void (*wlock_acquire)(void *lock),
           void (*lock_release)(void *lock),
           void (*lock_destroy)(void *lock),
	   void (*context_destroy)(void *context))
{
    static void *cur_context;
    static void (*cur_context_destroy)(void *);

    /* Just destroy the context from the previous call, if necessary. */
    if (cur_context_destroy != NULL)
	cur_context_destroy(cur_context);
    cur_context = context;
    cur_context_destroy = context_destroy;
}

void *
dlopen(const char *name, int mode)
{
    Obj_Entry **old_obj_tail;
    Obj_Entry *obj;
    Objlist initlist;
    int result, lockstate;

    ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
    if (ld_tracing != NULL)
	environ = (char **)*get_program_var_addr("environ");

    objlist_init(&initlist);

    lockstate = wlock_acquire(rtld_bind_lock);
    GDB_STATE(RT_ADD,NULL);

    old_obj_tail = obj_tail;
    obj = NULL;
    if (name == NULL) {
	obj = obj_main;
	obj->refcount++;
    } else {
	char *path = find_library(name, obj_main);
	if (path != NULL)
	    obj = load_object(path);
    }

    if (obj) {
	obj->dl_refcount++;
	if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL)
	    objlist_push_tail(&list_global, obj);
	mode &= RTLD_MODEMASK;
	if (*old_obj_tail != NULL) {		/* We loaded something new. */
	    assert(*old_obj_tail == obj);

	    result = load_needed_objects(obj);
	    if (result != -1 && ld_tracing)
		goto trace;

	    if (result == -1 ||
	      (init_dag(obj), relocate_objects(obj, mode == RTLD_NOW,
	       &obj_rtld)) == -1) {
		obj->dl_refcount--;
		unref_dag(obj);
		if (obj->refcount == 0)
		    unload_object(obj);
		obj = NULL;
	    } else {
		/* Make list of init functions to call. */
		initlist_add_objects(obj, &obj->next, &initlist);
	    }
	} else {

	    /* Bump the reference counts for objects on this DAG. */
	    ref_dag(obj);

	    if (ld_tracing)
		goto trace;
	}
    }

    GDB_STATE(RT_CONSISTENT,obj ? &obj->linkmap : NULL);

    /* Call the init functions with no locks held. */
    wlock_release(rtld_bind_lock, lockstate);
    objlist_call_init(&initlist);
    lockstate = wlock_acquire(rtld_bind_lock);
    objlist_clear(&initlist);
    wlock_release(rtld_bind_lock, lockstate);
    return obj;
trace:
    trace_loaded_objects(obj);
    wlock_release(rtld_bind_lock, lockstate);
    exit(0);
}

void *
dlsym(void *handle, const char *name)
{
    const Obj_Entry *obj;
    unsigned long hash;
    const Elf_Sym *def;
    const Obj_Entry *defobj;
    int lockstate;

    hash = elf_hash(name);
    def = NULL;
    defobj = NULL;

    lockstate = rlock_acquire(rtld_bind_lock);
    if (handle == NULL || handle == RTLD_NEXT ||
	handle == RTLD_DEFAULT || handle == RTLD_SELF) {
	void *retaddr;

	retaddr = __builtin_return_address(0);	/* __GNUC__ only */
	if ((obj = obj_from_addr(retaddr)) == NULL) {
	    _rtld_error("Cannot determine caller's shared object");
	    rlock_release(rtld_bind_lock, lockstate);
	    return NULL;
	}
	if (handle == NULL) {	/* Just the caller's shared object. */
	    def = symlook_obj(name, hash, obj, true);
	    defobj = obj;
	} else if (handle == RTLD_NEXT || /* Objects after caller's */
		   handle == RTLD_SELF) { /* ... caller included */
	    if (handle == RTLD_NEXT)
		obj = obj->next;
	    for (; obj != NULL; obj = obj->next) {
		if ((def = symlook_obj(name, hash, obj, true)) != NULL) {
		    defobj = obj;
		    break;
		}
	    }
	} else {
	    assert(handle == RTLD_DEFAULT);
	    def = symlook_default(name, hash, obj, &defobj, true);
	}
    } else {
	if ((obj = dlcheck(handle)) == NULL) {
	    rlock_release(rtld_bind_lock, lockstate);
	    return NULL;
	}

	if (obj->mainprog) {
	    DoneList donelist;

	    /* Search main program and all libraries loaded by it. */
	    donelist_init(&donelist);
	    def = symlook_list(name, hash, &list_main, &defobj, true,
	      &donelist);
	} else {
	    /*
	     * XXX - This isn't correct.  The search should include the whole
	     * DAG rooted at the given object.
	     */
	    def = symlook_obj(name, hash, obj, true);
	    defobj = obj;
	}
    }

    if (def != NULL) {
	rlock_release(rtld_bind_lock, lockstate);

	/*
	 * The value required by the caller is derived from the value
	 * of the symbol. For the ia64 architecture, we need to
	 * construct a function descriptor which the caller can use to
	 * call the function with the right 'gp' value. For other
	 * architectures and for non-functions, the value is simply
	 * the relocated value of the symbol.
	 */
	if (ELF_ST_TYPE(def->st_info) == STT_FUNC)
	    return make_function_pointer(def, defobj);
	else
	    return defobj->relocbase + def->st_value;
    }

    _rtld_error("Undefined symbol \"%s\"", name);
    rlock_release(rtld_bind_lock, lockstate);
    return NULL;
}

int
dladdr(const void *addr, Dl_info *info)
{
    const Obj_Entry *obj;
    const Elf_Sym *def;
    void *symbol_addr;
    unsigned long symoffset;
    int lockstate;

    lockstate = rlock_acquire(rtld_bind_lock);
    obj = obj_from_addr(addr);
    if (obj == NULL) {
        _rtld_error("No shared object contains address");
	rlock_release(rtld_bind_lock, lockstate);
        return 0;
    }
    info->dli_fname = obj->path;
    info->dli_fbase = obj->mapbase;
    info->dli_saddr = (void *)0;
    info->dli_sname = NULL;

    /*
     * Walk the symbol list looking for the symbol whose address is
     * closest to the address sent in.
     */
    for (symoffset = 0; symoffset < obj->nchains; symoffset++) {
        def = obj->symtab + symoffset;

        /*
         * For skip the symbol if st_shndx is either SHN_UNDEF or
         * SHN_COMMON.
         */
        if (def->st_shndx == SHN_UNDEF || def->st_shndx == SHN_COMMON)
            continue;

        /*
         * If the symbol is greater than the specified address, or if it
         * is further away from addr than the current nearest symbol,
         * then reject it.
         */
        symbol_addr = obj->relocbase + def->st_value;
        if (symbol_addr > addr || symbol_addr < info->dli_saddr)
            continue;

        /* Update our idea of the nearest symbol. */
        info->dli_sname = obj->strtab + def->st_name;
        info->dli_saddr = symbol_addr;

        /* Exact match? */
        if (info->dli_saddr == addr)
            break;
    }
    rlock_release(rtld_bind_lock, lockstate);
    return 1;
}

int
dlinfo(void *handle, int request, void *p)
{
    const Obj_Entry *obj;
    int error, lockstate;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -