dynlink.c 43.5 KB
Newer Older
1
#define _GNU_SOURCE
R
Rich Felker 已提交
2 3
#include <stdio.h>
#include <stdlib.h>
4
#include <stdarg.h>
5
#include <stddef.h>
R
Rich Felker 已提交
6 7 8 9 10 11 12 13 14
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <elf.h>
#include <sys/mman.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
R
Rich Felker 已提交
15
#include <link.h>
R
Rich Felker 已提交
16
#include <setjmp.h>
17
#include <pthread.h>
R
Rich Felker 已提交
18
#include <ctype.h>
19
#include <dlfcn.h>
20 21
#include "pthread_impl.h"
#include "libc.h"
R
Rich Felker 已提交
22
#include "dynlink.h"
R
Rich Felker 已提交
23

R
Rich Felker 已提交
24
static int errflag;
25
static char errbuf[128];
R
Rich Felker 已提交
26

27
#ifdef SHARED
R
Rich Felker 已提交
28

R
Rich Felker 已提交
29 30 31
#define MAXP2(a,b) (-(-(a)&-(b)))
#define ALIGN(x,y) ((x)+(y)-1 & -(y))

32 33 34 35 36 37 38 39
struct debug {
	int ver;
	void *head;
	void (*bp)(void);
	int state;
	void *base;
};

40 41 42 43 44
struct td_index {
	size_t args[2];
	struct td_index *next;
};

45 46 47 48
struct dso {
	unsigned char *base;
	char *name;
	size_t *dynv;
R
Rich Felker 已提交
49
	struct dso *next, *prev;
50

R
Rich Felker 已提交
51 52
	Phdr *phdr;
	int phnum;
53
	size_t phentsize;
R
Rich Felker 已提交
54 55
	int refcnt;
	Sym *syms;
56
	uint32_t *hashtab;
57
	uint32_t *ghashtab;
58
	int16_t *versym;
R
Rich Felker 已提交
59 60 61 62 63
	char *strings;
	unsigned char *map;
	size_t map_len;
	dev_t dev;
	ino_t ino;
64
	signed char global;
65 66
	char relocated;
	char constructed;
67
	char kernel_mapped;
68
	struct dso **deps, *needed_by;
69
	char *rpath_orig, *rpath;
70
	void *tls_image;
71
	size_t tls_len, tls_size, tls_align, tls_id, tls_offset;
T
Timo Teräs 已提交
72
	size_t relro_start, relro_end;
73 74
	void **new_dtv;
	unsigned char *new_tls;
75
	volatile int new_dtv_idx, new_tls_idx;
76
	struct td_index *td_index;
77
	struct dso *fini_next;
R
Rich Felker 已提交
78
	int rel_early_relative, rel_update_got;
79
	char *shortname;
R
Rich Felker 已提交
80
	char buf[];
R
Rich Felker 已提交
81 82
};

83 84 85 86 87
struct symdef {
	Sym *sym;
	struct dso *dso;
};

88
int __init_tp(void *);
89
void __init_libc(char **, char *);
90

91 92
const char *__libc_get_version(void);

93 94 95 96 97 98 99
static struct builtin_tls {
	char c;
	struct pthread pt;
	void *space[16];
} builtin_tls[1];
#define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt)

R
Rich Felker 已提交
100 101
static struct dso ldso;
static struct dso *head, *tail, *fini_head;
102
static char *env_path, *sys_path;
R
Rich Felker 已提交
103
static unsigned long long gencnt;
R
Rich Felker 已提交
104
static int runtime;
105
static int ldd_mode;
106
static int ldso_fail;
107
static int noload;
108
static jmp_buf *rtld_fail;
109
static pthread_rwlock_t lock;
110
static struct debug debug;
111
static size_t tls_cnt, tls_offset, tls_align = MIN_TLS_ALIGN;
112
static size_t static_tls_cnt;
113
static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE };
114 115

struct debug *_dl_debug_addr = &debug;
R
Rich Felker 已提交
116

R
Rich Felker 已提交
117 118 119 120 121 122
static int dl_strcmp(const char *l, const char *r)
{
	for (; *l==*r && *l; l++, r++);
	return *(unsigned char *)l - *(unsigned char *)r;
}
#define strcmp(l,r) dl_strcmp(l,r)
R
Rich Felker 已提交
123 124 125

static void decode_vec(size_t *v, size_t *a, size_t cnt)
{
R
Rich Felker 已提交
126 127 128 129
	size_t i;
	for (i=0; i<cnt; i++) a[i] = 0;
	for (; v[0]; v+=2) if (v[0]-1<cnt-1) {
		a[0] |= 1UL<<v[0];
R
Rich Felker 已提交
130 131 132 133
		a[v[0]] = v[1];
	}
}

134 135 136 137 138 139 140 141
static int search_vec(size_t *v, size_t *r, size_t key)
{
	for (; v[0]!=key; v+=2)
		if (!v[0]) return 0;
	*r = v[1];
	return 1;
}

142 143 144 145 146 147 148 149 150 151 152
static void error(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vsnprintf(errbuf, sizeof errbuf, fmt, ap);
	va_end(ap);
	if (runtime) longjmp(*rtld_fail, 1);
	dprintf(2, "%s\n", errbuf);
	ldso_fail = 1;
}

153
static uint32_t sysv_hash(const char *s0)
R
Rich Felker 已提交
154
{
155
	const unsigned char *s = (void *)s0;
R
Rich Felker 已提交
156 157 158 159 160 161 162 163
	uint_fast32_t h = 0;
	while (*s) {
		h = 16*h + *s++;
		h ^= h>>24 & 0xf0;
	}
	return h & 0xfffffff;
}

164 165 166 167 168 169 170 171 172 173
static uint32_t gnu_hash(const char *s0)
{
	const unsigned char *s = (void *)s0;
	uint_fast32_t h = 5381;
	for (; *s; s++)
		h = h*33 + *s;
	return h;
}

static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
R
Rich Felker 已提交
174 175
{
	size_t i;
R
Rich Felker 已提交
176 177 178
	Sym *syms = dso->syms;
	uint32_t *hashtab = dso->hashtab;
	char *strings = dso->strings;
R
Rich Felker 已提交
179
	for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) {
180 181
		if ((!dso->versym || dso->versym[i] >= 0)
		    && (!strcmp(s, strings+syms[i].st_name)))
R
Rich Felker 已提交
182 183 184 185 186
			return syms+i;
	}
	return 0;
}

187 188
static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
{
189 190
	Sym *syms = dso->syms;
	char *strings = dso->strings;
191 192 193 194 195
	uint32_t *hashtab = dso->ghashtab;
	uint32_t nbuckets = hashtab[0];
	uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4);
	uint32_t h2;
	uint32_t *hashval;
196
	uint32_t i = buckets[h1 % nbuckets];
197

198
	if (!i) return 0;
199

200
	hashval = buckets + nbuckets + (i - hashtab[1]);
201

202
	for (h1 |= 1; ; i++) {
203
		h2 = *hashval++;
204 205 206
		if ((!dso->versym || dso->versym[i] >= 0)
		    && (h1 == (h2|1)) && !strcmp(s, strings + syms[i].st_name))
			return syms+i;
207 208 209 210 211 212
		if (h2 & 1) break;
	}

	return 0;
}

213
#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON | 1<<STT_TLS)
214
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)
R
Rich Felker 已提交
215

216 217 218 219
#ifndef ARCH_SYM_REJECT_UND
#define ARCH_SYM_REJECT_UND(s) 0
#endif

220
static struct symdef find_sym(struct dso *dso, const char *s, int need_def)
R
Rich Felker 已提交
221
{
222
	uint32_t h = 0, gh = 0;
223
	struct symdef def = {0};
R
Rich Felker 已提交
224
	for (; dso; dso=dso->next) {
225 226
		Sym *sym;
		if (!dso->global) continue;
227 228 229 230 231 232 233
		if (dso->ghashtab) {
			if (!gh) gh = gnu_hash(s);
			sym = gnu_lookup(s, gh, dso);
		} else {
			if (!h) h = sysv_hash(s);
			sym = sysv_lookup(s, h, dso);
		}
234 235
		if (!sym) continue;
		if (!sym->st_shndx)
236 237
			if (need_def || (sym->st_info&0xf) == STT_TLS
			    || ARCH_SYM_REJECT_UND(sym))
238 239 240 241 242 243 244 245 246 247 248
				continue;
		if (!sym->st_value)
			if ((sym->st_info&0xf) != STT_TLS)
				continue;
		if (!(1<<(sym->st_info&0xf) & OK_TYPES)) continue;
		if (!(1<<(sym->st_info>>4) & OK_BINDS)) continue;

		if (def.sym && sym->st_info>>4 == STB_WEAK) continue;
		def.sym = sym;
		def.dso = dso;
		if (sym->st_info>>4 == STB_GLOBAL) break;
R
Rich Felker 已提交
249
	}
250
	return def;
R
Rich Felker 已提交
251 252
}

253 254
ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic();

255
static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride)
R
Rich Felker 已提交
256
{
257 258 259
	unsigned char *base = dso->base;
	Sym *syms = dso->syms;
	char *strings = dso->strings;
R
Rich Felker 已提交
260 261 262
	Sym *sym;
	const char *name;
	void *ctx;
R
Rich Felker 已提交
263
	int type;
R
Rich Felker 已提交
264
	int sym_index;
265
	struct symdef def;
266 267 268 269
	size_t *reloc_addr;
	size_t sym_val;
	size_t tls_val;
	size_t addend;
R
Rich Felker 已提交
270 271

	for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) {
R
Rich Felker 已提交
272 273
		if (dso->rel_early_relative && IS_RELATIVE(rel[1])) continue;
		type = R_TYPE(rel[1]);
R
Rich Felker 已提交
274
		sym_index = R_SYM(rel[1]);
275
		reloc_addr = (void *)(base + rel[0]);
R
Rich Felker 已提交
276 277 278
		if (sym_index) {
			sym = syms + sym_index;
			name = strings + sym->st_name;
279 280
			ctx = type==REL_COPY ? head->next : head;
			def = find_sym(ctx, name, type==REL_PLT);
281 282
			if (!def.sym && (sym->st_shndx != SHN_UNDEF
			    || sym->st_info>>4 != STB_WEAK)) {
283
				error("Error relocating %s: %s: symbol not found",
284
					dso->name, name);
285
				continue;
R
Rich Felker 已提交
286
			}
287
		} else {
288 289
			sym = 0;
			def.sym = 0;
290 291 292
			def.dso = dso;
		}

R
Rich Felker 已提交
293 294 295
		int gotplt = (type == REL_GOT || type == REL_PLT);
		if (dso->rel_update_got && !gotplt) continue;

296
		addend = stride>2 ? rel[2]
R
Rich Felker 已提交
297
			: gotplt || type==REL_COPY ? 0
298 299 300 301 302 303
			: *reloc_addr;

		sym_val = def.sym ? (size_t)def.dso->base+def.sym->st_value : 0;
		tls_val = def.sym ? def.sym->st_value : 0;

		switch(type) {
R
Rich Felker 已提交
304 305
		case REL_NONE:
			break;
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
		case REL_OFFSET:
			addend -= (size_t)reloc_addr;
		case REL_SYMBOLIC:
		case REL_GOT:
		case REL_PLT:
			*reloc_addr = sym_val + addend;
			break;
		case REL_RELATIVE:
			*reloc_addr = (size_t)base + addend;
			break;
		case REL_SYM_OR_REL:
			if (sym) *reloc_addr = sym_val + addend;
			else *reloc_addr = (size_t)base + addend;
			break;
		case REL_COPY:
			memcpy(reloc_addr, (void *)sym_val, sym->st_size);
			break;
		case REL_OFFSET32:
			*(uint32_t *)reloc_addr = sym_val + addend
				- (size_t)reloc_addr;
			break;
		case REL_DTPMOD:
			*reloc_addr = def.dso->tls_id;
			break;
		case REL_DTPOFF:
			*reloc_addr = tls_val + addend;
			break;
#ifdef TLS_ABOVE_TP
		case REL_TPOFF:
			*reloc_addr = tls_val + def.dso->tls_offset + TPOFF_K + addend;
			break;
#else
		case REL_TPOFF:
			*reloc_addr = tls_val - def.dso->tls_offset + addend;
			break;
		case REL_TPOFF_NEG:
			*reloc_addr = def.dso->tls_offset - tls_val + addend;
			break;
#endif
345 346 347 348
		case REL_TLSDESC:
			if (stride<3) addend = reloc_addr[1];
			if (runtime && def.dso->tls_id >= static_tls_cnt) {
				struct td_index *new = malloc(sizeof *new);
349
				if (!new) error(
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
					"Error relocating %s: cannot allocate TLSDESC for %s",
					dso->name, sym ? name : "(local)" );
				new->next = dso->td_index;
				dso->td_index = new;
				new->args[0] = def.dso->tls_id;
				new->args[1] = tls_val + addend;
				reloc_addr[0] = (size_t)__tlsdesc_dynamic;
				reloc_addr[1] = (size_t)new;
			} else {
				reloc_addr[0] = (size_t)__tlsdesc_static;
#ifdef TLS_ABOVE_TP
				reloc_addr[1] = tls_val + def.dso->tls_offset
					+ TPOFF_K + addend;
#else
				reloc_addr[1] = tls_val - def.dso->tls_offset
					+ addend;
#endif
			}
			break;
R
Rich Felker 已提交
369 370 371 372
		default:
			error("Error relocating %s: unsupported relocation type %d",
				dso->name, type);
			continue;
R
Rich Felker 已提交
373 374 375 376
		}
	}
}

377 378 379 380 381 382
/* A huge hack: to make up for the wastefulness of shared libraries
 * needing at least a page of dirty memory even if they have no global
 * data, we reclaim the gaps at the beginning and end of writable maps
 * and "donate" them to the heap by setting up minimal malloc
 * structures and then freeing them. */

T
Timo Teräs 已提交
383
static void reclaim(struct dso *dso, size_t start, size_t end)
384 385
{
	size_t *a, *z;
T
Timo Teräs 已提交
386 387
	if (start >= dso->relro_start && start < dso->relro_end) start = dso->relro_end;
	if (end   >= dso->relro_start && end   < dso->relro_end) end = dso->relro_start;
388 389 390
	start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t);
	end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t);
	if (start>end || end-start < 4*sizeof(size_t)) return;
T
Timo Teräs 已提交
391 392
	a = (size_t *)(dso->base + start);
	z = (size_t *)(dso->base + end);
393 394 395 396 397 398
	a[-2] = 1;
	a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1;
	z[1] = 1;
	free(a);
}

399
static void reclaim_gaps(struct dso *dso)
400
{
401 402
	Phdr *ph = dso->phdr;
	size_t phcnt = dso->phnum;
403

404
	for (; phcnt--; ph=(void *)((char *)ph+dso->phentsize)) {
405 406
		if (ph->p_type!=PT_LOAD) continue;
		if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
T
Timo Teräs 已提交
407 408
		reclaim(dso, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
		reclaim(dso, ph->p_vaddr+ph->p_memsz,
409 410 411 412
			ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE);
	}
}

413
static void *map_library(int fd, struct dso *dso)
R
Rich Felker 已提交
414
{
415
	Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
416
	void *allocated_buf=0;
R
Rich Felker 已提交
417 418 419 420 421
	size_t phsize;
	size_t addr_min=SIZE_MAX, addr_max=0, map_len;
	size_t this_min, this_max;
	off_t off_start;
	Ehdr *eh;
422
	Phdr *ph, *ph0;
R
Rich Felker 已提交
423
	unsigned prot;
424
	unsigned char *map=MAP_FAILED, *base;
425
	size_t dyn=0;
426
	size_t tls_image=0;
R
Rich Felker 已提交
427 428 429
	size_t i;

	ssize_t l = read(fd, buf, sizeof buf);
430
	eh = buf;
431 432 433
	if (l<0) return 0;
	if (l<sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC))
		goto noexec;
R
Rich Felker 已提交
434
	phsize = eh->e_phentsize * eh->e_phnum;
435 436 437 438 439 440 441 442
	if (phsize > sizeof buf - sizeof *eh) {
		allocated_buf = malloc(phsize);
		if (!allocated_buf) return 0;
		l = pread(fd, allocated_buf, phsize, eh->e_phoff);
		if (l < 0) goto error;
		if (l != phsize) goto noexec;
		ph = ph0 = allocated_buf;
	} else if (eh->e_phoff + phsize > l) {
443
		l = pread(fd, buf+1, phsize, eh->e_phoff);
444 445
		if (l < 0) goto error;
		if (l != phsize) goto noexec;
446 447 448
		ph = ph0 = (void *)(buf + 1);
	} else {
		ph = ph0 = (void *)((char *)buf + eh->e_phoff);
R
Rich Felker 已提交
449 450
	}
	for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
451
		if (ph->p_type == PT_DYNAMIC) {
R
Rich Felker 已提交
452
			dyn = ph->p_vaddr;
453
		} else if (ph->p_type == PT_TLS) {
454 455 456 457
			tls_image = ph->p_vaddr;
			dso->tls_align = ph->p_align;
			dso->tls_len = ph->p_filesz;
			dso->tls_size = ph->p_memsz;
T
Timo Teräs 已提交
458 459 460
		} else if (ph->p_type == PT_GNU_RELRO) {
			dso->relro_start = ph->p_vaddr & -PAGE_SIZE;
			dso->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
461
		}
R
Rich Felker 已提交
462 463 464 465 466 467 468 469 470 471 472 473
		if (ph->p_type != PT_LOAD) continue;
		if (ph->p_vaddr < addr_min) {
			addr_min = ph->p_vaddr;
			off_start = ph->p_offset;
			prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) |
				((ph->p_flags&PF_W) ? PROT_WRITE: 0) |
				((ph->p_flags&PF_X) ? PROT_EXEC : 0));
		}
		if (ph->p_vaddr+ph->p_memsz > addr_max) {
			addr_max = ph->p_vaddr+ph->p_memsz;
		}
	}
474
	if (!dyn) goto noexec;
R
Rich Felker 已提交
475 476 477 478 479 480 481 482 483
	addr_max += PAGE_SIZE-1;
	addr_max &= -PAGE_SIZE;
	addr_min &= -PAGE_SIZE;
	off_start &= -PAGE_SIZE;
	map_len = addr_max - addr_min + off_start;
	/* The first time, we map too much, possibly even more than
	 * the length of the file. This is okay because we will not
	 * use the invalid part; we just need to reserve the right
	 * amount of virtual address space to map over later. */
484
	map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
485
	if (map==MAP_FAILED) goto error;
486 487 488 489 490 491
	/* If the loaded file is not relocatable and the requested address is
	 * not available, then the load operation must fail. */
	if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) {
		errno = EBUSY;
		goto error;
	}
R
Rich Felker 已提交
492
	base = map - addr_min;
493 494 495
	dso->phdr = 0;
	dso->phnum = 0;
	for (ph=ph0, i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
R
Rich Felker 已提交
496
		if (ph->p_type != PT_LOAD) continue;
497 498 499 500 501 502 503
		/* Check if the programs headers are in this load segment, and
		 * if so, record the address for use by dl_iterate_phdr. */
		if (!dso->phdr && eh->e_phoff >= ph->p_offset
		    && eh->e_phoff+phsize <= ph->p_offset+ph->p_filesz) {
			dso->phdr = (void *)(base + ph->p_vaddr
				+ (eh->e_phoff-ph->p_offset));
			dso->phnum = eh->e_phnum;
504
			dso->phentsize = eh->e_phentsize;
505
		}
R
Rich Felker 已提交
506 507 508 509 510 511 512 513
		/* Reuse the existing mapping for the lowest-address LOAD */
		if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue;
		this_min = ph->p_vaddr & -PAGE_SIZE;
		this_max = ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE;
		off_start = ph->p_offset & -PAGE_SIZE;
		prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) |
			((ph->p_flags&PF_W) ? PROT_WRITE: 0) |
			((ph->p_flags&PF_X) ? PROT_EXEC : 0));
514 515
		if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED)
			goto error;
R
Rich Felker 已提交
516 517 518 519
		if (ph->p_memsz > ph->p_filesz) {
			size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz;
			size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE;
			memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1);
520 521
			if (pgbrk-(size_t)base < this_max && mmap((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED)
				goto error;
R
Rich Felker 已提交
522 523
		}
	}
R
Rich Felker 已提交
524 525
	for (i=0; ((size_t *)(base+dyn))[i]; i+=2)
		if (((size_t *)(base+dyn))[i]==DT_TEXTREL) {
526 527
			if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) < 0)
				goto error;
R
Rich Felker 已提交
528 529
			break;
		}
530 531 532 533 534
	dso->map = map;
	dso->map_len = map_len;
	dso->base = base;
	dso->dynv = (void *)(base+dyn);
	if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
535
	if (!runtime) reclaim_gaps(dso);
536
	free(allocated_buf);
R
Rich Felker 已提交
537
	return map;
538 539
noexec:
	errno = ENOEXEC;
540
error:
541 542
	if (map!=MAP_FAILED) munmap(map, map_len);
	free(allocated_buf);
543
	return 0;
R
Rich Felker 已提交
544 545
}

546
static int path_open(const char *name, const char *s, char *buf, size_t buf_size)
547
{
548 549
	size_t l;
	int fd;
550
	for (;;) {
551 552 553
		s += strspn(s, ":\n");
		l = strcspn(s, ":\n");
		if (l-1 >= INT_MAX) return -1;
554 555 556 557 558 559 560 561 562 563 564 565 566 567
		if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) {
			if ((fd = open(buf, O_RDONLY|O_CLOEXEC))>=0) return fd;
			switch (errno) {
			case ENOENT:
			case ENOTDIR:
			case EACCES:
			case ENAMETOOLONG:
				break;
			default:
				/* Any negative value but -1 will inhibit
				 * futher path search. */
				return -2;
			}
		}
568
		s += l;
569 570 571
	}
}

572 573 574 575 576
static int fixup_rpath(struct dso *p, char *buf, size_t buf_size)
{
	size_t n, l;
	const char *s, *t, *origin;
	char *d;
577
	if (p->rpath || !p->rpath_orig) return 0;
578 579 580 581 582 583
	if (!strchr(p->rpath_orig, '$')) {
		p->rpath = p->rpath_orig;
		return 0;
	}
	n = 0;
	s = p->rpath_orig;
R
Rich Felker 已提交
584 585
	while ((t=strchr(s, '$'))) {
		if (strncmp(t, "$ORIGIN", 7) && strncmp(t, "${ORIGIN}", 9))
586
			return 0;
587 588 589
		s = t+1;
		n++;
	}
590
	if (n > SSIZE_MAX/PATH_MAX) return 0;
591 592 593 594 595 596 597 598 599

	if (p->kernel_mapped) {
		/* $ORIGIN searches cannot be performed for the main program
		 * when it is suid/sgid/AT_SECURE. This is because the
		 * pathname is under the control of the caller of execve.
		 * For libraries, however, $ORIGIN can be processed safely
		 * since the library's pathname came from a trusted source
		 * (either system paths or a call to dlopen). */
		if (libc.secure)
600
			return 0;
R
Rich Felker 已提交
601
		l = readlink("/proc/self/exe", buf, buf_size);
602 603 604 605 606 607
		if (l == -1) switch (errno) {
		case ENOENT:
		case ENOTDIR:
		case EACCES:
			break;
		default:
608
			return -1;
609 610 611
		}
		if (l >= buf_size)
			return 0;
R
Rich Felker 已提交
612
		buf[l] = 0;
613 614 615 616 617 618 619 620 621 622 623
		origin = buf;
	} else {
		origin = p->name;
	}
	t = strrchr(origin, '/');
	l = t ? t-origin : 0;
	p->rpath = malloc(strlen(p->rpath_orig) + n*l + 1);
	if (!p->rpath) return -1;

	d = p->rpath;
	s = p->rpath_orig;
R
Rich Felker 已提交
624
	while ((t=strchr(s, '$'))) {
625 626 627 628
		memcpy(d, s, t-s);
		d += t-s;
		memcpy(d, origin, l);
		d += l;
R
Rich Felker 已提交
629 630
		/* It was determined previously that the '$' is followed
		 * either by "ORIGIN" or "{ORIGIN}". */
631 632 633 634 635 636
		s = t + 7 + 2*(t[1]=='{');
	}
	strcpy(d, s);
	return 0;
}

637 638
static void decode_dyn(struct dso *p)
{
639
	size_t dyn[DYN_CNT];
640 641 642
	decode_vec(p->dynv, dyn, DYN_CNT);
	p->syms = (void *)(p->base + dyn[DT_SYMTAB]);
	p->strings = (void *)(p->base + dyn[DT_STRTAB]);
643 644
	if (dyn[0]&(1<<DT_HASH))
		p->hashtab = (void *)(p->base + dyn[DT_HASH]);
645
	if (dyn[0]&(1<<DT_RPATH))
646
		p->rpath_orig = (void *)(p->strings + dyn[DT_RPATH]);
647 648
	if (dyn[0]&(1<<DT_RUNPATH))
		p->rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]);
649 650
	if (search_vec(p->dynv, dyn, DT_GNU_HASH))
		p->ghashtab = (void *)(p->base + *dyn);
651 652
	if (search_vec(p->dynv, dyn, DT_VERSYM))
		p->versym = (void *)(p->base + *dyn);
653 654
}

655
static struct dso *load_library(const char *name, struct dso *needed_by)
R
Rich Felker 已提交
656
{
657
	char buf[2*NAME_MAX+2];
658
	const char *pathname;
659
	unsigned char *map;
660
	struct dso *p, temp_dso = {0};
R
Rich Felker 已提交
661 662
	int fd;
	struct stat st;
663 664
	size_t alloc_size;
	int n_th = 0;
665
	int is_self = 0;
R
Rich Felker 已提交
666

667 668 669 670 671
	if (!*name) {
		errno = EINVAL;
		return 0;
	}

R
Rich Felker 已提交
672 673 674 675 676 677 678
	/* Catch and block attempts to reload the implementation itself */
	if (name[0]=='l' && name[1]=='i' && name[2]=='b') {
		static const char *rp, reserved[] =
			"c\0pthread\0rt\0m\0dl\0util\0xnet\0";
		char *z = strchr(name, '.');
		if (z) {
			size_t l = z-name;
679
			for (rp=reserved; *rp && strncmp(name+3, rp, l-3); rp+=strlen(rp)+1);
R
Rich Felker 已提交
680
			if (*rp) {
681 682 683 684 685 686 687 688
				if (ldd_mode) {
					/* Track which names have been resolved
					 * and only report each one once. */
					static unsigned reported;
					unsigned mask = 1U<<(rp-reserved);
					if (!(reported & mask)) {
						reported |= mask;
						dprintf(1, "\t%s => %s (%p)\n",
R
Rich Felker 已提交
689 690
							name, ldso.name,
							ldso.base);
691 692
					}
				}
693
				is_self = 1;
R
Rich Felker 已提交
694 695 696
			}
		}
	}
R
Rich Felker 已提交
697
	if (!strcmp(name, ldso.name)) is_self = 1;
698
	if (is_self) {
R
Rich Felker 已提交
699 700 701 702
		if (!ldso.prev) {
			tail->next = &ldso;
			ldso.prev = tail;
			tail = ldso.next ? ldso.next : &ldso;
703
		}
R
Rich Felker 已提交
704
		return &ldso;
705
	}
706
	if (strchr(name, '/')) {
707
		pathname = name;
708
		fd = open(name, O_RDONLY|O_CLOEXEC);
R
Rich Felker 已提交
709
	} else {
710 711 712 713 714 715 716
		/* Search for the name to see if it's already loaded */
		for (p=head->next; p; p=p->next) {
			if (p->shortname && !strcmp(p->shortname, name)) {
				p->refcnt++;
				return p;
			}
		}
717
		if (strlen(name) > NAME_MAX) return 0;
718
		fd = -1;
719
		if (env_path) fd = path_open(name, env_path, buf, sizeof buf);
720 721 722 723
		for (p=needed_by; fd == -1 && p; p=p->needed_by) {
			if (fixup_rpath(p, buf, sizeof buf) < 0)
				fd = -2; /* Inhibit further search. */
			if (p->rpath)
724
				fd = path_open(name, p->rpath, buf, sizeof buf);
725
		}
726
		if (fd == -1) {
727
			if (!sys_path) {
728 729
				char *prefix = 0;
				size_t prefix_len;
R
Rich Felker 已提交
730
				if (ldso.name[0]=='/') {
731
					char *s, *t, *z;
R
Rich Felker 已提交
732
					for (s=t=z=ldso.name; *s; s++)
733
						if (*s=='/') z=t, t=s;
R
Rich Felker 已提交
734
					prefix_len = z-ldso.name;
735
					if (prefix_len < PATH_MAX)
R
Rich Felker 已提交
736
						prefix = ldso.name;
737 738 739 740 741 742 743 744 745 746 747
				}
				if (!prefix) {
					prefix = "";
					prefix_len = 0;
				}
				char etc_ldso_path[prefix_len + 1
					+ sizeof "/etc/ld-musl-" LDSO_ARCH ".path"];
				snprintf(etc_ldso_path, sizeof etc_ldso_path,
					"%.*s/etc/ld-musl-" LDSO_ARCH ".path",
					(int)prefix_len, prefix);
				FILE *f = fopen(etc_ldso_path, "rbe");
748
				if (f) {
749
					if (getdelim(&sys_path, (size_t[1]){0}, 0, f) <= 0) {
750
						free(sys_path);
751
						sys_path = "";
752
					}
753
					fclose(f);
754 755
				} else if (errno != ENOENT) {
					sys_path = "";
756 757
				}
			}
758 759
			if (!sys_path) sys_path = "/lib:/usr/local/lib:/usr/lib";
			fd = path_open(name, sys_path, buf, sizeof buf);
R
Rich Felker 已提交
760
		}
761
		pathname = buf;
R
Rich Felker 已提交
762 763 764 765 766 767 768 769
	}
	if (fd < 0) return 0;
	if (fstat(fd, &st) < 0) {
		close(fd);
		return 0;
	}
	for (p=head->next; p; p=p->next) {
		if (p->dev == st.st_dev && p->ino == st.st_ino) {
770 771 772
			/* If this library was previously loaded with a
			 * pathname but a search found the same inode,
			 * setup its shortname so it can be found by name. */
773 774
			if (!p->shortname && pathname != name)
				p->shortname = strrchr(p->name, '/')+1;
R
Rich Felker 已提交
775 776 777 778 779
			close(fd);
			p->refcnt++;
			return p;
		}
	}
780
	map = noload ? 0 : map_library(fd, &temp_dso);
R
Rich Felker 已提交
781 782
	close(fd);
	if (!map) return 0;
783 784 785 786 787 788 789 790 791 792

	/* Allocate storage for the new DSO. When there is TLS, this
	 * storage must include a reservation for all pre-existing
	 * threads to obtain copies of both the new TLS, and an
	 * extended DTV capable of storing an additional slot for
	 * the newly-loaded DSO. */
	alloc_size = sizeof *p + strlen(pathname) + 1;
	if (runtime && temp_dso.tls_image) {
		size_t per_th = temp_dso.tls_size + temp_dso.tls_align
			+ sizeof(void *) * (tls_cnt+3);
793
		n_th = libc.threads_minus_1 + 1;
794 795 796 797
		if (n_th > SSIZE_MAX / per_th) alloc_size = SIZE_MAX;
		else alloc_size += n_th * per_th;
	}
	p = calloc(1, alloc_size);
R
Rich Felker 已提交
798
	if (!p) {
799
		munmap(map, temp_dso.map_len);
R
Rich Felker 已提交
800 801
		return 0;
	}
802
	memcpy(p, &temp_dso, sizeof temp_dso);
803
	decode_dyn(p);
R
Rich Felker 已提交
804 805 806
	p->dev = st.st_dev;
	p->ino = st.st_ino;
	p->refcnt = 1;
807
	p->needed_by = needed_by;
R
Rich Felker 已提交
808
	p->name = p->buf;
809 810 811
	strcpy(p->name, pathname);
	/* Add a shortname only if name arg was not an explicit pathname. */
	if (pathname != name) p->shortname = strrchr(p->name, '/')+1;
812 813
	if (p->tls_image) {
		p->tls_id = ++tls_cnt;
R
Rich Felker 已提交
814
		tls_align = MAXP2(tls_align, p->tls_align);
815 816 817 818 819
#ifdef TLS_ABOVE_TP
		p->tls_offset = tls_offset + ( (tls_align-1) &
			-(tls_offset + (uintptr_t)p->tls_image) );
		tls_offset += p->tls_size;
#else
R
Rich Felker 已提交
820 821 822 823
		tls_offset += p->tls_size + p->tls_align - 1;
		tls_offset -= (tls_offset + (uintptr_t)p->tls_image)
			& (p->tls_align-1);
		p->tls_offset = tls_offset;
824
#endif
825 826 827 828
		p->new_dtv = (void *)(-sizeof(size_t) &
			(uintptr_t)(p->name+strlen(p->name)+sizeof(size_t)));
		p->new_tls = (void *)(p->new_dtv + n_th*(tls_cnt+1));
	}
R
Rich Felker 已提交
829 830 831 832 833

	tail->next = p;
	p->prev = tail;
	tail = p;

834
	if (ldd_mode) dprintf(1, "\t%s => %s (%p)\n", name, pathname, p->base);
835

R
Rich Felker 已提交
836 837 838 839 840
	return p;
}

static void load_deps(struct dso *p)
{
841 842
	size_t i, ndeps=0;
	struct dso ***deps = &p->deps, **tmp, *dep;
R
Rich Felker 已提交
843 844 845
	for (; p; p=p->next) {
		for (i=0; p->dynv[i]; i+=2) {
			if (p->dynv[i] != DT_NEEDED) continue;
846
			dep = load_library(p->strings + p->dynv[i+1], p);
847
			if (!dep) {
848
				error("Error loading shared library %s: %m (needed by %s)",
R
Rich Felker 已提交
849
					p->strings + p->dynv[i+1], p->name);
850
				continue;
R
Rich Felker 已提交
851
			}
852 853
			if (runtime) {
				tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2));
854
				if (!tmp) longjmp(*rtld_fail, 1);
855 856 857 858
				tmp[ndeps++] = dep;
				tmp[ndeps] = 0;
				*deps = tmp;
			}
R
Rich Felker 已提交
859 860 861 862
		}
	}
}

R
Rich Felker 已提交
863 864 865 866 867
static void load_preload(char *s)
{
	int tmp;
	char *z;
	for (z=s; *z; s=z) {
868 869
		for (   ; *s && (isspace(*s) || *s==':'); s++);
		for (z=s; *z && !isspace(*z) && *z!=':'; z++);
R
Rich Felker 已提交
870 871
		tmp = *z;
		*z = 0;
872
		load_library(s, 0);
R
Rich Felker 已提交
873 874 875 876
		*z = tmp;
	}
}

877 878 879 880 881
static void make_global(struct dso *p)
{
	for (; p; p=p->next) p->global = 1;
}

R
Rich Felker 已提交
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901
static void do_mips_relocs(struct dso *p, size_t *got)
{
	size_t i, j, rel[2];
	unsigned char *base = p->base;
	i=0; search_vec(p->dynv, &i, DT_MIPS_LOCAL_GOTNO);
	if (p->rel_early_relative) {
		got += i;
	} else {
		while (i--) *got++ += (size_t)base;
	}
	j=0; search_vec(p->dynv, &j, DT_MIPS_GOTSYM);
	i=0; search_vec(p->dynv, &i, DT_MIPS_SYMTABNO);
	Sym *sym = p->syms + j;
	rel[0] = (unsigned char *)got - base;
	for (i-=j; i; i--, sym++, rel[0]+=sizeof(size_t)) {
		rel[1] = sym-p->syms << 8 | R_MIPS_JUMP_SLOT;
		do_relocs(p, rel, sizeof rel, 2);
	}
}

R
Rich Felker 已提交
902 903
static void reloc_all(struct dso *p)
{
904
	size_t dyn[DYN_CNT];
R
Rich Felker 已提交
905 906 907
	for (; p; p=p->next) {
		if (p->relocated) continue;
		decode_vec(p->dynv, dyn, DYN_CNT);
R
Rich Felker 已提交
908 909
		if (NEED_MIPS_GOT_RELOCS)
			do_mips_relocs(p, (void *)(p->base+dyn[DT_PLTGOT]));
910 911 912 913
		do_relocs(p, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ],
			2+(dyn[DT_PLTREL]==DT_RELA));
		do_relocs(p, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], 2);
		do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3);
T
Timo Teräs 已提交
914

R
Rich Felker 已提交
915
		if (head != &ldso && p->relro_start != p->relro_end &&
T
Timo Teräs 已提交
916
		    mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) {
917
			error("Error relocating %s: RELRO protection failed: %m",
T
Timo Teräs 已提交
918 919 920
				p->name);
		}

921
		p->relocated = 1;
R
Rich Felker 已提交
922 923 924
	}
}

925
static void kernel_mapped_dso(struct dso *p)
926
{
927 928 929 930 931 932
	size_t min_addr = -1, max_addr = 0, cnt;
	Phdr *ph = p->phdr;
	for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) {
		if (ph->p_type == PT_DYNAMIC) {
			p->dynv = (void *)(p->base + ph->p_vaddr);
		} else if (ph->p_type == PT_GNU_RELRO) {
T
Timo Teräs 已提交
933 934 935
			p->relro_start = ph->p_vaddr & -PAGE_SIZE;
			p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
		}
936 937 938 939 940 941 942 943 944 945
		if (ph->p_type != PT_LOAD) continue;
		if (ph->p_vaddr < min_addr)
			min_addr = ph->p_vaddr;
		if (ph->p_vaddr+ph->p_memsz > max_addr)
			max_addr = ph->p_vaddr+ph->p_memsz;
	}
	min_addr &= -PAGE_SIZE;
	max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE;
	p->map = p->base + min_addr;
	p->map_len = max_addr - min_addr;
946
	p->kernel_mapped = 1;
947 948
}

949 950 951
static void do_fini()
{
	struct dso *p;
952
	size_t dyn[DYN_CNT];
953 954 955
	for (p=fini_head; p; p=p->fini_next) {
		if (!p->constructed) continue;
		decode_vec(p->dynv, dyn, DYN_CNT);
956 957
		if (dyn[0] & (1<<DT_FINI_ARRAY)) {
			size_t n = dyn[DT_FINI_ARRAYSZ]/sizeof(size_t);
958 959
			size_t *fn = (size_t *)(p->base + dyn[DT_FINI_ARRAY])+n;
			while (n--) ((void (*)(void))*--fn)();
960
		}
961
#ifndef NO_LEGACY_INITFINI
962
		if ((dyn[0] & (1<<DT_FINI)) && dyn[DT_FINI])
963
			((void (*)(void))(p->base + dyn[DT_FINI]))();
964
#endif
965 966 967
	}
}

968 969
static void do_init_fini(struct dso *p)
{
970
	size_t dyn[DYN_CNT];
971
	int need_locking = libc.threads_minus_1;
972 973 974 975
	/* Allow recursive calls that arise when a library calls
	 * dlopen from one of its constructors, but block any
	 * other threads until all ctors have finished. */
	if (need_locking) pthread_mutex_lock(&init_fini_lock);
976
	for (; p; p=p->prev) {
977 978
		if (p->constructed) continue;
		p->constructed = 1;
979
		decode_vec(p->dynv, dyn, DYN_CNT);
980
		if (dyn[0] & ((1<<DT_FINI) | (1<<DT_FINI_ARRAY))) {
981 982 983
			p->fini_next = fini_head;
			fini_head = p;
		}
984
#ifndef NO_LEGACY_INITFINI
985
		if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT])
986
			((void (*)(void))(p->base + dyn[DT_INIT]))();
987
#endif
988 989 990 991 992
		if (dyn[0] & (1<<DT_INIT_ARRAY)) {
			size_t n = dyn[DT_INIT_ARRAYSZ]/sizeof(size_t);
			size_t *fn = (void *)(p->base + dyn[DT_INIT_ARRAY]);
			while (n--) ((void (*)(void))*fn++)();
		}
993 994 995 996
		if (!need_locking && libc.threads_minus_1) {
			need_locking = 1;
			pthread_mutex_lock(&init_fini_lock);
		}
997
	}
998
	if (need_locking) pthread_mutex_unlock(&init_fini_lock);
999 1000
}

1001 1002 1003 1004
void _dl_debug_state(void)
{
}

1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
void __reset_tls()
{
	pthread_t self = __pthread_self();
	struct dso *p;
	for (p=head; p; p=p->next) {
		if (!p->tls_id || !self->dtv[p->tls_id]) continue;
		memcpy(self->dtv[p->tls_id], p->tls_image, p->tls_len);
		memset((char *)self->dtv[p->tls_id]+p->tls_len, 0,
			p->tls_size - p->tls_len);
		if (p->tls_id == (size_t)self->dtv[0]) break;
	}
}

1018
void *__copy_tls(unsigned char *mem)
1019
{
R
Rich Felker 已提交
1020
	pthread_t td;
1021
	struct dso *p;
1022
	void **dtv;
R
Rich Felker 已提交
1023

1024
#ifdef TLS_ABOVE_TP
1025 1026
	dtv = (void **)(mem + libc.tls_size) - (tls_cnt + 1);

1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
	mem += -((uintptr_t)mem + sizeof(struct pthread)) & (tls_align-1);
	td = (pthread_t)mem;
	mem += sizeof(struct pthread);

	for (p=head; p; p=p->next) {
		if (!p->tls_id) continue;
		dtv[p->tls_id] = mem + p->tls_offset;
		memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
	}
#else
1037 1038
	dtv = (void **)mem;

1039
	mem += libc.tls_size - sizeof(struct pthread);
R
Rich Felker 已提交
1040 1041 1042 1043
	mem -= (uintptr_t)mem & (tls_align-1);
	td = (pthread_t)mem;

	for (p=head; p; p=p->next) {
1044
		if (!p->tls_id) continue;
R
Rich Felker 已提交
1045 1046
		dtv[p->tls_id] = mem - p->tls_offset;
		memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
1047
	}
1048
#endif
1049
	dtv[0] = (void *)tls_cnt;
1050
	td->dtv = td->dtv_copy = dtv;
R
Rich Felker 已提交
1051
	return td;
1052 1053
}

1054
void *__tls_get_new(size_t *v)
1055 1056
{
	pthread_t self = __pthread_self();
1057 1058 1059

	/* Block signals to make accessing new TLS async-signal-safe */
	sigset_t set;
1060
	__block_all_sigs(&set);
1061
	if (v[0]<=(size_t)self->dtv[0]) {
1062
		__restore_sigs(&set);
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
		return (char *)self->dtv[v[0]]+v[1];
	}

	/* This is safe without any locks held because, if the caller
	 * is able to request the Nth entry of the DTV, the DSO list
	 * must be valid at least that far out and it was synchronized
	 * at program startup or by an already-completed call to dlopen. */
	struct dso *p;
	for (p=head; p->tls_id != v[0]; p=p->next);

	/* Get new DTV space from new DSO if needed */
1074
	if (v[0] > (size_t)self->dtv[0]) {
1075 1076
		void **newdtv = p->new_dtv +
			(v[0]+1)*sizeof(void *)*a_fetch_add(&p->new_dtv_idx,1);
1077
		memcpy(newdtv, self->dtv,
1078 1079
			((size_t)self->dtv[0]+1) * sizeof(void *));
		newdtv[0] = (void *)v[0];
1080
		self->dtv = self->dtv_copy = newdtv;
1081
	}
1082

1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
	/* Get new TLS memory from all new DSOs up to the requested one */
	unsigned char *mem;
	for (p=head; ; p=p->next) {
		if (!p->tls_id || self->dtv[p->tls_id]) continue;
		mem = p->new_tls + (p->tls_size + p->tls_align)
			* a_fetch_add(&p->new_tls_idx,1);
		mem += ((uintptr_t)p->tls_image - (uintptr_t)mem)
			& (p->tls_align-1);
		self->dtv[p->tls_id] = mem;
		memcpy(mem, p->tls_image, p->tls_len);
		if (p->tls_id == v[0]) break;
	}
1095
	__restore_sigs(&set);
1096
	return mem + v[1];
1097 1098
}

R
Rich Felker 已提交
1099 1100
static void update_tls_size()
{
1101 1102 1103 1104 1105 1106
	libc.tls_size = ALIGN(
		(1+tls_cnt) * sizeof(void *) +
		tls_offset +
		sizeof(struct pthread) +
		tls_align * 2,
	tls_align);
R
Rich Felker 已提交
1107 1108
}

R
Rich Felker 已提交
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
/* Stage 1 of the dynamic linker is defined in dlstart.c. It calls the
 * following stage 2 and stage 3 functions via primitive symbolic lookup
 * since it does not have access to their addresses to begin with. */

/* Stage 2 of the dynamic linker is called after relative relocations 
 * have been processed. It can make function calls to static functions
 * and access string literals and static data, but cannot use extern
 * symbols. Its job is to perform symbolic relocations on the dynamic
 * linker itself, but some of the relocations performed may need to be
 * replaced later due to copy relocations in the main program. */

void __dls2(unsigned char *base)
R
Rich Felker 已提交
1121
{
R
Rich Felker 已提交
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
	Ehdr *ehdr = (void *)base;
	ldso.base = base;
	ldso.name = ldso.shortname = "libc.so";
	ldso.global = 1;
	ldso.phnum = ehdr->e_phnum;
	ldso.phdr = (void *)(base + ehdr->e_phoff);
	ldso.phentsize = ehdr->e_phentsize;
	ldso.rel_early_relative = 1;
	kernel_mapped_dso(&ldso);
	decode_dyn(&ldso);

	head = &ldso;
	reloc_all(&ldso);

	ldso.relocated = 0;
	ldso.rel_update_got = 1;
}

/* Stage 3 of the dynamic linker is called with the dynamic linker/libc
 * fully functional. Its job is to load (if not already loaded) and
 * process dependencies and relocations for the main application and
 * transfer control to its entry point. */

_Noreturn void __dls3(size_t *sp)
{
	static struct dso app, vdso;
1148
	size_t aux[AUX_CNT], *auxv;
R
Rich Felker 已提交
1149
	size_t i;
R
Rich Felker 已提交
1150
	char *env_preload=0;
R
Rich Felker 已提交
1151
	size_t vdso_base;
R
Rich Felker 已提交
1152 1153 1154
	int argc = *sp;
	char **argv = (void *)(sp+1);
	char **argv_orig = argv;
1155
	char **envp = argv+argc+1;
1156 1157 1158 1159 1160 1161

	/* Setup early thread pointer in builtin_tls for ldso/libc itself to
	 * use during dynamic linking. If possible it will also serve as the
	 * thread pointer at runtime. */
	libc.tls_size = sizeof builtin_tls;
	if (__init_tp(__copy_tls((void *)builtin_tls)) < 0) {
1162
		a_crash();
1163
	}
R
Rich Felker 已提交
1164 1165

	/* Find aux vector just past environ[] */
1166 1167 1168
	for (i=argc+1; argv[i]; i++)
		if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16))
			env_path = argv[i]+16;
R
Rich Felker 已提交
1169 1170
		else if (!memcmp(argv[i], "LD_PRELOAD=", 11))
			env_preload = argv[i]+11;
R
Rich Felker 已提交
1171 1172 1173 1174
	auxv = (void *)(argv+i+1);

	decode_vec(auxv, aux, AUX_CNT);

1175 1176
	/* Only trust user/env if kernel says we're not suid/sgid */
	if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID]
R
Rich Felker 已提交
1177
	  || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
1178
		env_path = 0;
R
Rich Felker 已提交
1179
		env_preload = 0;
1180
		libc.secure = 1;
1181
	}
1182
	libc.page_size = aux[AT_PAGESZ];
1183
	libc.auxv = auxv;
1184

R
Rich Felker 已提交
1185 1186 1187 1188
	/* If the main program was already loaded by the kernel,
	 * AT_PHDR will point to some location other than the dynamic
	 * linker's program headers. */
	if (aux[AT_PHDR] != (size_t)ldso.phdr) {
1189
		size_t interp_off = 0;
1190
		size_t tls_image = 0;
1191
		/* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
R
Rich Felker 已提交
1192 1193 1194
		Phdr *phdr = app.phdr = (void *)aux[AT_PHDR];
		app.phnum = aux[AT_PHNUM];
		app.phentsize = aux[AT_PHENT];
1195 1196
		for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
			if (phdr->p_type == PT_PHDR)
R
Rich Felker 已提交
1197
				app.base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
1198 1199
			else if (phdr->p_type == PT_INTERP)
				interp_off = (size_t)phdr->p_vaddr;
1200 1201
			else if (phdr->p_type == PT_TLS) {
				tls_image = phdr->p_vaddr;
R
Rich Felker 已提交
1202 1203 1204
				app.tls_len = phdr->p_filesz;
				app.tls_size = phdr->p_memsz;
				app.tls_align = phdr->p_align;
1205
			}
1206
		}
R
Rich Felker 已提交
1207 1208
		if (app.tls_size) app.tls_image = (char *)app.base + tls_image;
		if (interp_off) ldso.name = (char *)app.base + interp_off;
1209 1210
		if ((aux[0] & (1UL<<AT_EXECFN))
		    && strncmp((char *)aux[AT_EXECFN], "/proc/", 6))
R
Rich Felker 已提交
1211
			app.name = (char *)aux[AT_EXECFN];
1212
		else
R
Rich Felker 已提交
1213 1214
			app.name = argv[0];
		kernel_mapped_dso(&app);
1215 1216 1217
	} else {
		int fd;
		char *ldname = argv[0];
R
Rich Felker 已提交
1218
		size_t l = strlen(ldname);
1219
		if (l >= 3 && !strcmp(ldname+l-3, "ldd")) ldd_mode = 1;
R
Rich Felker 已提交
1220
		argv++;
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
		while (argv[0] && argv[0][0]=='-' && argv[0][1]=='-') {
			char *opt = argv[0]+2;
			*argv++ = (void *)-1;
			if (!*opt) {
				break;
			} else if (!memcmp(opt, "list", 5)) {
				ldd_mode = 1;
			} else if (!memcmp(opt, "library-path", 12)) {
				if (opt[12]=='=') env_path = opt+13;
				else if (opt[12]) *argv = 0;
				else if (*argv) env_path = *argv++;
			} else if (!memcmp(opt, "preload", 7)) {
				if (opt[7]=='=') env_preload = opt+8;
				else if (opt[7]) *argv = 0;
				else if (*argv) env_preload = *argv++;
			} else {
				argv[0] = 0;
			}
		}
R
Rich Felker 已提交
1240
		argv[-1] = (void *)(argc - (argv-argv_orig));
1241
		if (!argv[0]) {
1242 1243 1244
			dprintf(2, "musl libc\n"
				"Version %s\n"
				"Dynamic Program Loader\n"
1245
				"Usage: %s [options] [--] pathname%s\n",
1246
				__libc_get_version(), ldname,
1247 1248 1249 1250 1251 1252 1253 1254 1255
				ldd_mode ? "" : " [args]");
			_exit(1);
		}
		fd = open(argv[0], O_RDONLY);
		if (fd < 0) {
			dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno));
			_exit(1);
		}
		runtime = 1;
R
Rich Felker 已提交
1256
		Ehdr *ehdr = (void *)map_library(fd, &app);
1257 1258 1259 1260 1261 1262
		if (!ehdr) {
			dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]);
			_exit(1);
		}
		runtime = 0;
		close(fd);
R
Rich Felker 已提交
1263 1264 1265
		ldso.name = ldname;
		app.name = argv[0];
		aux[AT_ENTRY] = (size_t)app.base + ehdr->e_entry;
1266 1267 1268
		/* Find the name that would have been used for the dynamic
		 * linker had ldd not taken its place. */
		if (ldd_mode) {
R
Rich Felker 已提交
1269 1270 1271 1272
			for (i=0; i<app.phnum; i++) {
				if (app.phdr[i].p_type == PT_INTERP)
					ldso.name = (void *)(app.base
						+ app.phdr[i].p_vaddr);
1273
			}
R
Rich Felker 已提交
1274
			dprintf(1, "\t%s (%p)\n", ldso.name, ldso.base);
1275
		}
1276
	}
R
Rich Felker 已提交
1277 1278
	if (app.tls_size) {
		app.tls_id = tls_cnt = 1;
1279
#ifdef TLS_ABOVE_TP
R
Rich Felker 已提交
1280 1281 1282 1283
		app.tls_offset = 0;
		tls_offset = app.tls_size
			+ ( -((uintptr_t)app.tls_image + app.tls_size)
			& (app.tls_align-1) );
1284
#else
R
Rich Felker 已提交
1285 1286 1287
		tls_offset = app.tls_offset = app.tls_size
			+ ( -((uintptr_t)app.tls_image + app.tls_size)
			& (app.tls_align-1) );
1288
#endif
R
Rich Felker 已提交
1289
		tls_align = MAXP2(tls_align, app.tls_align);
1290
	}
R
Rich Felker 已提交
1291 1292
	app.global = 1;
	decode_dyn(&app);
1293 1294

	/* Attach to vdso, if provided by the kernel */
R
Rich Felker 已提交
1295
	if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) {
R
Rich Felker 已提交
1296 1297 1298 1299
		Ehdr *ehdr = (void *)vdso_base;
		Phdr *phdr = vdso.phdr = (void *)(vdso_base + ehdr->e_phoff);
		vdso.phnum = ehdr->e_phnum;
		vdso.phentsize = ehdr->e_phentsize;
1300 1301
		for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
			if (phdr->p_type == PT_DYNAMIC)
R
Rich Felker 已提交
1302
				vdso.dynv = (void *)(vdso_base + phdr->p_offset);
1303
			if (phdr->p_type == PT_LOAD)
R
Rich Felker 已提交
1304
				vdso.base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset);
1305
		}
R
Rich Felker 已提交
1306 1307 1308 1309 1310 1311 1312
		vdso.name = "";
		vdso.shortname = "linux-gate.so.1";
		vdso.global = 1;
		vdso.relocated = 1;
		decode_dyn(&vdso);
		vdso.prev = &ldso;
		ldso.next = &vdso;
1313 1314
	}

R
Rich Felker 已提交
1315 1316
	/* Initial dso chain consists only of the app. */
	head = tail = &app;
R
Rich Felker 已提交
1317

1318
	/* Donate unused parts of app and library mapping to malloc */
R
Rich Felker 已提交
1319 1320
	reclaim_gaps(&app);
	reclaim_gaps(&ldso);
1321

1322
	/* Load preload/needed libraries, add their symbols to the global
R
Rich Felker 已提交
1323
	 * namespace, and perform all remaining relocations. */
R
Rich Felker 已提交
1324
	if (env_preload) load_preload(env_preload);
R
Rich Felker 已提交
1325 1326
	load_deps(&app);
	make_global(&app);
1327

T
Timo Teräs 已提交
1328
#ifndef DYNAMIC_IS_RO
R
Rich Felker 已提交
1329 1330 1331
	for (i=0; app.dynv[i]; i+=2)
		if (app.dynv[i]==DT_DEBUG)
			app.dynv[i+1] = (size_t)&debug;
T
Timo Teräs 已提交
1332 1333
#endif

R
Rich Felker 已提交
1334 1335 1336 1337
	/* The main program must be relocated LAST since it may contin
	 * copy relocations which depend on libraries' relocations. */
	reloc_all(app.next);
	reloc_all(&app);
R
Rich Felker 已提交
1338 1339

	update_tls_size();
1340 1341
	if (libc.tls_size > sizeof builtin_tls || tls_align > MIN_TLS_ALIGN) {
		void *initial_tls = calloc(libc.tls_size, 1);
1342
		if (!initial_tls) {
1343
			dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n",
1344
				argv[0], libc.tls_size);
1345 1346
			_exit(127);
		}
1347
		if (__init_tp(__copy_tls(initial_tls)) < 0) {
1348
			a_crash();
1349
		}
1350
	} else {
1351 1352 1353 1354 1355 1356 1357 1358
		size_t tmp_tls_size = libc.tls_size;
		pthread_t self = __pthread_self();
		/* Temporarily set the tls size to the full size of
		 * builtin_tls so that __copy_tls will use the same layout
		 * as it did for before. Then check, just to be safe. */
		libc.tls_size = sizeof builtin_tls;
		if (__copy_tls((void*)builtin_tls) != self) a_crash();
		libc.tls_size = tmp_tls_size;
1359
	}
1360
	static_tls_cnt = tls_cnt;
1361

1362
	if (ldso_fail) _exit(127);
1363 1364
	if (ldd_mode) _exit(0);

1365 1366
	/* Switch to runtime mode: any further failures in the dynamic
	 * linker are a reportable failure rather than a fatal startup
R
Rich Felker 已提交
1367
	 * error. */
R
Rich Felker 已提交
1368
	runtime = 1;
1369

1370 1371 1372
	debug.ver = 1;
	debug.bp = _dl_debug_state;
	debug.head = head;
R
Rich Felker 已提交
1373
	debug.base = ldso.base;
1374 1375 1376
	debug.state = 0;
	_dl_debug_state();

1377
	__init_libc(envp, argv[0]);
1378
	atexit(do_fini);
1379
	errno = 0;
1380
	do_init_fini(tail);
1381

R
Rich Felker 已提交
1382 1383
	CRTJMP((void *)aux[AT_ENTRY], argv-1);
	for(;;);
1384 1385
}

1386 1387
void *dlopen(const char *file, int mode)
{
R
Rich Felker 已提交
1388
	struct dso *volatile p, *orig_tail, *next;
R
Rich Felker 已提交
1389
	size_t orig_tls_cnt, orig_tls_offset, orig_tls_align;
1390
	size_t i;
1391
	int cs;
1392
	jmp_buf jb;
1393 1394 1395

	if (!file) return head;

1396
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
1397
	pthread_rwlock_wrlock(&lock);
1398
	__inhibit_ptc();
1399

1400 1401
	p = 0;
	orig_tls_cnt = tls_cnt;
R
Rich Felker 已提交
1402 1403
	orig_tls_offset = tls_offset;
	orig_tls_align = tls_align;
R
Rich Felker 已提交
1404
	orig_tail = tail;
1405
	noload = mode & RTLD_NOLOAD;
R
Rich Felker 已提交
1406

1407 1408
	rtld_fail = &jb;
	if (setjmp(*rtld_fail)) {
1409
		/* Clean up anything new that was (partially) loaded */
1410
		if (p && p->deps) for (i=0; p->deps[i]; i++)
1411 1412
			if (p->deps[i]->global < 0)
				p->deps[i]->global = 0;
1413 1414 1415
		for (p=orig_tail->next; p; p=next) {
			next = p->next;
			munmap(p->map, p->map_len);
1416 1417 1418 1419 1420
			while (p->td_index) {
				void *tmp = p->td_index->next;
				free(p->td_index);
				p->td_index = tmp;
			}
1421 1422
			if (p->rpath != p->rpath_orig)
				free(p->rpath);
1423 1424 1425
			free(p->deps);
			free(p);
		}
1426
		tls_cnt = orig_tls_cnt;
R
Rich Felker 已提交
1427 1428
		tls_offset = orig_tls_offset;
		tls_align = orig_tls_align;
1429 1430
		tail = orig_tail;
		tail->next = 0;
1431
		p = 0;
1432 1433
		errflag = 1;
		goto end;
1434
	} else p = load_library(file, head);
R
Rich Felker 已提交
1435 1436

	if (!p) {
1437 1438 1439 1440
		snprintf(errbuf, sizeof errbuf, noload ?
			"Library %s is not already loaded" :
			"Error loading shared library %s: %m",
			file);
R
Rich Felker 已提交
1441
		errflag = 1;
1442
		goto end;
1443 1444 1445 1446 1447
	}

	/* First load handling */
	if (!p->deps) {
		load_deps(p);
R
Rich Felker 已提交
1448
		if (p->deps) for (i=0; p->deps[i]; i++)
1449 1450 1451
			if (!p->deps[i]->global)
				p->deps[i]->global = -1;
		if (!p->global) p->global = -1;
1452
		reloc_all(p);
R
Rich Felker 已提交
1453
		if (p->deps) for (i=0; p->deps[i]; i++)
1454 1455 1456
			if (p->deps[i]->global < 0)
				p->deps[i]->global = 0;
		if (p->global < 0) p->global = 0;
1457 1458 1459
	}

	if (mode & RTLD_GLOBAL) {
R
Rich Felker 已提交
1460
		if (p->deps) for (i=0; p->deps[i]; i++)
1461 1462 1463 1464
			p->deps[i]->global = 1;
		p->global = 1;
	}

R
Rich Felker 已提交
1465
	update_tls_size();
1466
	_dl_debug_state();
1467
	orig_tail = tail;
1468
end:
1469
	__release_ptc();
R
Rich Felker 已提交
1470
	if (p) gencnt++;
1471
	pthread_rwlock_unlock(&lock);
1472
	if (p) do_init_fini(orig_tail);
1473
	pthread_setcancelstate(cs, 0);
1474 1475 1476
	return p;
}

1477
static int invalid_dso_handle(void *h)
1478 1479 1480 1481 1482 1483 1484 1485
{
	struct dso *p;
	for (p=head; p; p=p->next) if (h==p) return 0;
	snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
	errflag = 1;
	return 1;
}

1486 1487
void *__tls_get_addr(size_t *);

R
Rich Felker 已提交
1488
static void *do_dlsym(struct dso *p, const char *s, void *ra)
1489 1490
{
	size_t i;
1491
	uint32_t h = 0, gh = 0;
1492
	Sym *sym;
1493
	if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) {
1494 1495 1496
		if (p == RTLD_DEFAULT) {
			p = head;
		} else if (p == RTLD_NEXT) {
1497 1498
			for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
			if (!p) p=head;
1499
			p = p->next;
1500
		}
1501
		struct symdef def = find_sym(p, s, 0);
1502
		if (!def.sym) goto failed;
1503 1504
		if ((def.sym->st_info&0xf) == STT_TLS)
			return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value});
1505
		return def.dso->base + def.sym->st_value;
R
Rich Felker 已提交
1506
	}
1507 1508
	if (p != RTLD_DEFAULT && p != RTLD_NEXT && invalid_dso_handle(p))
		return 0;
1509 1510 1511 1512 1513 1514 1515
	if (p->ghashtab) {
		gh = gnu_hash(s);
		sym = gnu_lookup(s, gh, p);
	} else {
		h = sysv_hash(s);
		sym = sysv_lookup(s, h, p);
	}
1516 1517
	if (sym && (sym->st_info&0xf) == STT_TLS)
		return __tls_get_addr((size_t []){p->tls_id, sym->st_value});
1518 1519 1520
	if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
		return p->base + sym->st_value;
	if (p->deps) for (i=0; p->deps[i]; i++) {
1521 1522
		if (p->deps[i]->ghashtab) {
			if (!gh) gh = gnu_hash(s);
1523
			sym = gnu_lookup(s, gh, p->deps[i]);
1524 1525 1526 1527
		} else {
			if (!h) h = sysv_hash(s);
			sym = sysv_lookup(s, h, p->deps[i]);
		}
1528 1529
		if (sym && (sym->st_info&0xf) == STT_TLS)
			return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value});
1530 1531 1532
		if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
			return p->deps[i]->base + sym->st_value;
	}
1533
failed:
R
Rich Felker 已提交
1534
	errflag = 1;
1535
	snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
1536 1537 1538
	return 0;
}

1539
int __dladdr(const void *addr, Dl_info *info)
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563
{
	struct dso *p;
	Sym *sym;
	uint32_t nsym;
	char *strings;
	size_t i;
	void *best = 0;
	char *bestname;

	pthread_rwlock_rdlock(&lock);
	for (p=head; p && (unsigned char *)addr-p->map>p->map_len; p=p->next);
	pthread_rwlock_unlock(&lock);

	if (!p) return 0;

	sym = p->syms;
	strings = p->strings;
	if (p->hashtab) {
		nsym = p->hashtab[1];
	} else {
		uint32_t *buckets;
		uint32_t *hashval;
		buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4);
		sym += p->ghashtab[1];
R
Rich Felker 已提交
1564
		for (i = nsym = 0; i < p->ghashtab[0]; i++) {
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576
			if (buckets[i] > nsym)
				nsym = buckets[i];
		}
		if (nsym) {
			nsym -= p->ghashtab[1];
			hashval = buckets + p->ghashtab[0] + nsym;
			do nsym++;
			while (!(*hashval++ & 1));
		}
	}

	for (; nsym; nsym--, sym++) {
1577
		if (sym->st_value
1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
		 && (1<<(sym->st_info&0xf) & OK_TYPES)
		 && (1<<(sym->st_info>>4) & OK_BINDS)) {
			void *symaddr = p->base + sym->st_value;
			if (symaddr > addr || symaddr < best)
				continue;
			best = symaddr;
			bestname = strings + sym->st_name;
			if (addr == symaddr)
				break;
		}
	}

	if (!best) return 0;

	info->dli_fname = p->name;
	info->dli_fbase = p->base;
	info->dli_sname = bestname;
	info->dli_saddr = best;

	return 1;
}

1600
void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
1601 1602 1603
{
	void *res;
	pthread_rwlock_rdlock(&lock);
R
Rich Felker 已提交
1604
	res = do_dlsym(p, s, ra);
1605 1606 1607
	pthread_rwlock_unlock(&lock);
	return res;
}
R
Rich Felker 已提交
1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633

int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void *data), void *data)
{
	struct dso *current;
	struct dl_phdr_info info;
	int ret = 0;
	for(current = head; current;) {
		info.dlpi_addr      = (uintptr_t)current->base;
		info.dlpi_name      = current->name;
		info.dlpi_phdr      = current->phdr;
		info.dlpi_phnum     = current->phnum;
		info.dlpi_adds      = gencnt;
		info.dlpi_subs      = 0;
		info.dlpi_tls_modid = current->tls_id;
		info.dlpi_tls_data  = current->tls_image;

		ret = (callback)(&info, sizeof (info), data);

		if (ret != 0) break;

		pthread_rwlock_rdlock(&lock);
		current = current->next;
		pthread_rwlock_unlock(&lock);
	}
	return ret;
}
1634
#else
1635
static int invalid_dso_handle(void *h)
1636 1637 1638 1639 1640
{
	snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
	errflag = 1;
	return 1;
}
1641 1642
void *dlopen(const char *file, int mode)
{
1643 1644
	strcpy(errbuf, "Dynamic loading not supported");
	errflag = 1;
1645 1646
	return 0;
}
1647
void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
1648
{
1649 1650
	errflag = 1;
	snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
1651 1652
	return 0;
}
1653
int __dladdr (const void *addr, Dl_info *info)
1654 1655 1656
{
	return 0;
}
1657
#endif
1658

R
Rich Felker 已提交
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670
int __dlinfo(void *dso, int req, void *res)
{
	if (invalid_dso_handle(dso)) return -1;
	if (req != RTLD_DI_LINKMAP) {
		snprintf(errbuf, sizeof errbuf, "Unsupported request %d", req);
		errflag = 1;
		return -1;
	}
	*(struct link_map **)res = dso;
	return 0;
}

1671 1672
char *dlerror()
{
R
Rich Felker 已提交
1673 1674
	if (!errflag) return 0;
	errflag = 0;
1675
	return errbuf;
1676 1677 1678 1679
}

int dlclose(void *p)
{
1680
	return invalid_dso_handle(p);
1681
}