Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/libc/musl/ldso/dlstart.c
6174 views
1
#include <stddef.h>
2
#include "dynlink.h"
3
#include "libc.h"
4
5
#ifndef START
6
#define START "_dlstart"
7
#endif
8
9
#define SHARED
10
11
#include "crt_arch.h"
12
13
#ifndef GETFUNCSYM
14
#define GETFUNCSYM(fp, sym, got) do { \
15
hidden void sym(); \
16
static void (*static_func_ptr)() = sym; \
17
__asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \
18
*(fp) = static_func_ptr; } while(0)
19
#endif
20
21
hidden void _dlstart_c(size_t *sp, size_t *dynv)
22
{
23
size_t i, aux[AUX_CNT], dyn[DYN_CNT];
24
size_t *rel, rel_size, base;
25
26
int argc = *sp;
27
char **argv = (void *)(sp+1);
28
29
for (i=argc+1; argv[i]; i++);
30
size_t *auxv = (void *)(argv+i+1);
31
32
for (i=0; i<AUX_CNT; i++) aux[i] = 0;
33
for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)
34
aux[auxv[i]] = auxv[i+1];
35
36
#if DL_FDPIC
37
struct fdpic_loadseg *segs, fakeseg;
38
size_t j;
39
if (dynv) {
40
/* crt_arch.h entry point asm is responsible for reserving
41
* space and moving the extra fdpic arguments to the stack
42
* vector where they are easily accessible from C. */
43
segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;
44
} else {
45
/* If dynv is null, the entry point was started from loader
46
* that is not fdpic-aware. We can assume normal fixed-
47
* displacement ELF loading was performed, but when ldso was
48
* run as a command, finding the Ehdr is a heursitic: we
49
* have to assume Phdrs start in the first 4k of the file. */
50
base = aux[AT_BASE];
51
if (!base) base = aux[AT_PHDR] & -4096;
52
segs = &fakeseg;
53
segs[0].addr = base;
54
segs[0].p_vaddr = 0;
55
segs[0].p_memsz = -1;
56
Ehdr *eh = (void *)base;
57
Phdr *ph = (void *)(base + eh->e_phoff);
58
size_t phnum = eh->e_phnum;
59
size_t phent = eh->e_phentsize;
60
while (phnum-- && ph->p_type != PT_DYNAMIC)
61
ph = (void *)((size_t)ph + phent);
62
dynv = (void *)(base + ph->p_vaddr);
63
}
64
#endif
65
66
for (i=0; i<DYN_CNT; i++) dyn[i] = 0;
67
for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)
68
dyn[dynv[i]] = dynv[i+1];
69
70
#if DL_FDPIC
71
for (i=0; i<DYN_CNT; i++) {
72
if (i==DT_RELASZ || i==DT_RELSZ) continue;
73
if (!dyn[i]) continue;
74
for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
75
dyn[i] += segs[j].addr - segs[j].p_vaddr;
76
}
77
base = 0;
78
79
const Sym *syms = (void *)dyn[DT_SYMTAB];
80
81
rel = (void *)dyn[DT_RELA];
82
rel_size = dyn[DT_RELASZ];
83
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
84
if (!IS_RELATIVE(rel[1], syms)) continue;
85
for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
86
size_t *rel_addr = (void *)
87
(rel[0] + segs[j].addr - segs[j].p_vaddr);
88
if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {
89
*rel_addr += segs[rel_addr[1]].addr
90
- segs[rel_addr[1]].p_vaddr
91
+ syms[R_SYM(rel[1])].st_value;
92
rel_addr[1] = dyn[DT_PLTGOT];
93
} else {
94
size_t val = syms[R_SYM(rel[1])].st_value;
95
for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);
96
*rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;
97
}
98
}
99
#else
100
/* If the dynamic linker is invoked as a command, its load
101
* address is not available in the aux vector. Instead, compute
102
* the load address as the difference between &_DYNAMIC and the
103
* virtual address in the PT_DYNAMIC program header. */
104
base = aux[AT_BASE];
105
if (!base) {
106
size_t phnum = aux[AT_PHNUM];
107
size_t phentsize = aux[AT_PHENT];
108
Phdr *ph = (void *)aux[AT_PHDR];
109
for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {
110
if (ph->p_type == PT_DYNAMIC) {
111
base = (size_t)dynv - ph->p_vaddr;
112
break;
113
}
114
}
115
}
116
117
/* MIPS uses an ugly packed form for GOT relocations. Since we
118
* can't make function calls yet and the code is tiny anyway,
119
* it's simply inlined here. */
120
if (NEED_MIPS_GOT_RELOCS) {
121
size_t local_cnt = 0;
122
size_t *got = (void *)(base + dyn[DT_PLTGOT]);
123
for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)
124
local_cnt = dynv[i+1];
125
for (i=0; i<local_cnt; i++) got[i] += base;
126
}
127
128
rel = (void *)(base+dyn[DT_REL]);
129
rel_size = dyn[DT_RELSZ];
130
for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {
131
if (!IS_RELATIVE(rel[1], 0)) continue;
132
size_t *rel_addr = (void *)(base + rel[0]);
133
*rel_addr += base;
134
}
135
136
rel = (void *)(base+dyn[DT_RELA]);
137
rel_size = dyn[DT_RELASZ];
138
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
139
if (!IS_RELATIVE(rel[1], 0)) continue;
140
size_t *rel_addr = (void *)(base + rel[0]);
141
*rel_addr = base + rel[2];
142
}
143
144
rel = (void *)(base+dyn[DT_RELR]);
145
rel_size = dyn[DT_RELRSZ];
146
size_t *relr_addr = 0;
147
for (; rel_size; rel++, rel_size-=sizeof(size_t)) {
148
if ((rel[0]&1) == 0) {
149
relr_addr = (void *)(base + rel[0]);
150
*relr_addr++ += base;
151
} else {
152
for (size_t i=0, bitmap=rel[0]; bitmap>>=1; i++)
153
if (bitmap&1)
154
relr_addr[i] += base;
155
relr_addr += 8*sizeof(size_t)-1;
156
}
157
}
158
#endif
159
160
stage2_func dls2;
161
GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);
162
dls2((void *)base, sp);
163
}
164
165