1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;
}
|