aboutsummaryrefslogtreecommitdiff
path: root/user/lib/ld-weenix/ldresolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'user/lib/ld-weenix/ldresolve.c')
-rw-r--r--user/lib/ld-weenix/ldresolve.c119
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;
+}