diff options
author | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
---|---|---|
committer | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
commit | c63f340d90800895f007de64b7d2d14624263331 (patch) | |
tree | 2c0849fa597dd6da831c8707b6f2603403778d7b /user/lib/ld-weenix/ldresolve.c |
Created student weenix repository
Diffstat (limited to 'user/lib/ld-weenix/ldresolve.c')
-rw-r--r-- | user/lib/ld-weenix/ldresolve.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/user/lib/ld-weenix/ldresolve.c b/user/lib/ld-weenix/ldresolve.c new file mode 100644 index 0000000..db1da80 --- /dev/null +++ b/user/lib/ld-weenix/ldresolve.c @@ -0,0 +1,119 @@ +/* + * File: ldresolve.c + * Date: 12 April 1998 + * Acct: David Powell (dep) + * Desc: Various symbol resolution functions + * + * + * Acct: Sandy Harvie (charvie) + * Date: 27 March 2019 + * Desc: Modified for x86-64 + */ + +#include "string.h" + +#include "ldresolve.h" +#include "ldutil.h" + +#define H_nbucket 0 +#define H_nchain 1 +#define H_bucket 2 + +/* This function looks up the specified symbol in the specified + * module. If the symbol is present, it returns the symbol's index in + * the dynamic symbol table, otherwise STN_UNDEF is returned. */ + +int _ldlookup(module_t *module, const char *name) +{ + unsigned long hashval; + unsigned long y; + + hashval = _ldelfhash(name); + hashval %= module->hash[H_nbucket]; + + y = module->hash[H_bucket + hashval]; + + while ((y != STN_UNDEF) && + strcmp(module->dynstr + module->dynsym[y].st_name, name)) + { + y = module->hash[H_bucket + module->hash[H_nbucket] + y]; + } + + return y; +} + +/* This looks up the specified symbol in the given module, subject to + * the provided binding and type restrictions (a value of -1 will + * function as a wildcard for both the 'binding' and 'type' + * parameters). The symbol's size will be placed in the memory + * location pointed to by 'size', if it is non-null. 0 is returned if + * a symbol matching all the requirements is not found. */ + +ldsym_t _ldsymbol(module_t *module, const char *name, int binding, int type, + Elf64_Word *size) +{ + int result; + + /* LINTED */ + if (((result = _ldlookup(module, name)) != STN_UNDEF) && + ((binding < 0) || + (ELF64_ST_BIND(module->dynsym[result].st_info) == binding)) && + ((type < 0) || + (ELF64_ST_TYPE(module->dynsym[result].st_info) == type)) && + (module->dynsym[result].st_shndx != SHN_UNDEF)) + { + if (size) + *size = module->dynsym[result].st_size; + return (ldsym_t)((uintptr_t)module->base + + (uintptr_t)module->dynsym[result].st_value); + } + + return 0; +} + +/* Given a module and a symbol name, this function attempts to find the + * symbol through the process' link chain. It first checks for its + * presence as a global symbol, then as a weak symbol, and finally as a + * local symbol in the specified module. A type restriction can be + * specified, and if 'size' is non-null, the memory location to which + * it points will hold the size of the resolved symbol. 0 is returned + * if the symbol cannot be found. */ + +ldsym_t _ldresolve(module_t *module, const char *name, int type, + Elf64_Word *size, int exclude) +{ + module_t *curmod; + ldsym_t sym; + + curmod = module->first; + + while (curmod) + { + if (!exclude || curmod != module) + { + if ((sym = _ldsymbol(curmod, name, STB_GLOBAL, type, size))) + return sym; + } + curmod = curmod->next; + } + + curmod = module->first; + while (curmod) + { + if ((sym = _ldsymbol(curmod, name, STB_WEAK, type, size))) + return sym; + curmod = curmod->next; + } + + return _ldsymbol(module, name, STB_LOCAL, type, size); +} + +Elf64_Addr _rtresolve(module_t *mod, Elf64_Word reloff) +{ + Elf64_Rela *rel = mod->pltreloc + reloff; + int sym = ELF64_R_SYM(rel->r_info); + const char *name = mod->dynstr + mod->dynsym[sym].st_name; + ldsym_t symbol = _ldresolve(mod, name, -1, 0, 0); + *(Elf64_Addr *)(mod->base + rel->r_offset) = (Elf64_Addr)symbol; + return (Elf64_Addr)symbol; +} |