dynlink.c 43.2 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 639 640 641 642
static void decode_dyn(struct dso *p)
{
	size_t dyn[DYN_CNT] = {0};
	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
	if (p->tls_image) {
813
		if (runtime && !libc.has_thread_pointer) {
814
			munmap(map, p->map_len);
815
			free(p);
816
			errno = ENOSYS;
817 818
			return 0;
		}
819
		p->tls_id = ++tls_cnt;
R
Rich Felker 已提交
820
		tls_align = MAXP2(tls_align, p->tls_align);
821 822 823 824 825
#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 已提交
826 827 828 829
		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;
830
#endif
831 832 833 834
		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 已提交
835 836 837 838 839

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

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

R
Rich Felker 已提交
842 843 844 845 846
	return p;
}

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

R
Rich Felker 已提交
869 870 871 872 873
static void load_preload(char *s)
{
	int tmp;
	char *z;
	for (z=s; *z; s=z) {
874 875
		for (   ; *s && (isspace(*s) || *s==':'); s++);
		for (z=s; *z && !isspace(*z) && *z!=':'; z++);
R
Rich Felker 已提交
876 877
		tmp = *z;
		*z = 0;
878
		load_library(s, 0);
R
Rich Felker 已提交
879 880 881 882
		*z = tmp;
	}
}

883 884 885 886 887
static void make_global(struct dso *p)
{
	for (; p; p=p->next) p->global = 1;
}

R
Rich Felker 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
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 已提交
908 909 910 911 912 913
static void reloc_all(struct dso *p)
{
	size_t dyn[DYN_CNT] = {0};
	for (; p; p=p->next) {
		if (p->relocated) continue;
		decode_vec(p->dynv, dyn, DYN_CNT);
R
Rich Felker 已提交
914 915
		if (NEED_MIPS_GOT_RELOCS)
			do_mips_relocs(p, (void *)(p->base+dyn[DT_PLTGOT]));
916 917 918 919
		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 已提交
920

R
Rich Felker 已提交
921
		if (head != &ldso && p->relro_start != p->relro_end &&
T
Timo Teräs 已提交
922
		    mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) {
923
			error("Error relocating %s: RELRO protection failed: %m",
T
Timo Teräs 已提交
924 925 926
				p->name);
		}

927
		p->relocated = 1;
R
Rich Felker 已提交
928 929 930
	}
}

931
static void kernel_mapped_dso(struct dso *p)
932
{
933 934 935 936 937 938
	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 已提交
939 940 941
			p->relro_start = ph->p_vaddr & -PAGE_SIZE;
			p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE;
		}
942 943 944 945 946 947 948 949 950 951
		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;
952
	p->kernel_mapped = 1;
953 954
}

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

974 975 976
static void do_init_fini(struct dso *p)
{
	size_t dyn[DYN_CNT] = {0};
977
	int need_locking = libc.threads_minus_1;
978 979 980 981
	/* 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);
982
	for (; p; p=p->prev) {
983 984
		if (p->constructed) continue;
		p->constructed = 1;
985
		decode_vec(p->dynv, dyn, DYN_CNT);
986
		if (dyn[0] & ((1<<DT_FINI) | (1<<DT_FINI_ARRAY))) {
987 988 989
			p->fini_next = fini_head;
			fini_head = p;
		}
990
#ifndef NO_LEGACY_INITFINI
991
		if ((dyn[0] & (1<<DT_INIT)) && dyn[DT_INIT])
992
			((void (*)(void))(p->base + dyn[DT_INIT]))();
993
#endif
994 995 996 997 998
		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++)();
		}
999 1000 1001 1002
		if (!need_locking && libc.threads_minus_1) {
			need_locking = 1;
			pthread_mutex_lock(&init_fini_lock);
		}
1003
	}
1004
	if (need_locking) pthread_mutex_unlock(&init_fini_lock);
1005 1006
}

1007 1008 1009 1010
void _dl_debug_state(void)
{
}

1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
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;
	}
}

1024
void *__copy_tls(unsigned char *mem)
1025
{
R
Rich Felker 已提交
1026
	pthread_t td;
1027
	struct dso *p;
R
Rich Felker 已提交
1028

1029
	void **dtv = (void *)mem;
1030
	dtv[0] = (void *)tls_cnt;
1031 1032
	if (!tls_cnt) {
		td = (void *)(dtv+1);
1033
		td->dtv = td->dtv_copy = dtv;
1034 1035
		return td;
	}
R
Rich Felker 已提交
1036

1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
#ifdef TLS_ABOVE_TP
	mem += sizeof(void *) * (tls_cnt+1);
	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
1049
	mem += libc.tls_size - sizeof(struct pthread);
R
Rich Felker 已提交
1050 1051 1052 1053
	mem -= (uintptr_t)mem & (tls_align-1);
	td = (pthread_t)mem;

	for (p=head; p; p=p->next) {
1054
		if (!p->tls_id) continue;
R
Rich Felker 已提交
1055 1056
		dtv[p->tls_id] = mem - p->tls_offset;
		memcpy(dtv[p->tls_id], p->tls_image, p->tls_len);
1057
	}
1058
#endif
1059
	td->dtv = td->dtv_copy = dtv;
R
Rich Felker 已提交
1060
	return td;
1061 1062
}

1063
void *__tls_get_new(size_t *v)
1064 1065
{
	pthread_t self = __pthread_self();
1066 1067 1068

	/* Block signals to make accessing new TLS async-signal-safe */
	sigset_t set;
1069
	__block_all_sigs(&set);
1070
	if (v[0]<=(size_t)self->dtv[0]) {
1071
		__restore_sigs(&set);
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
		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 */
1083
	if (v[0] > (size_t)self->dtv[0]) {
1084 1085
		void **newdtv = p->new_dtv +
			(v[0]+1)*sizeof(void *)*a_fetch_add(&p->new_dtv_idx,1);
1086
		memcpy(newdtv, self->dtv,
1087 1088
			((size_t)self->dtv[0]+1) * sizeof(void *));
		newdtv[0] = (void *)v[0];
1089
		self->dtv = self->dtv_copy = newdtv;
1090
	}
1091

1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
	/* 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;
	}
1104
	__restore_sigs(&set);
1105
	return mem + v[1];
1106 1107
}

R
Rich Felker 已提交
1108 1109
static void update_tls_size()
{
1110 1111 1112 1113 1114 1115
	libc.tls_size = ALIGN(
		(1+tls_cnt) * sizeof(void *) +
		tls_offset +
		sizeof(struct pthread) +
		tls_align * 2,
	tls_align);
R
Rich Felker 已提交
1116 1117
}

R
Rich Felker 已提交
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129
/* 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 已提交
1130
{
R
Rich Felker 已提交
1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
	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;
	size_t aux[AUX_CNT] = {0}, *auxv;
R
Rich Felker 已提交
1158
	size_t i;
R
Rich Felker 已提交
1159
	char *env_preload=0;
R
Rich Felker 已提交
1160
	size_t vdso_base;
R
Rich Felker 已提交
1161 1162 1163
	int argc = *sp;
	char **argv = (void *)(sp+1);
	char **argv_orig = argv;
1164
	char **envp = argv+argc+1;
1165
	void *initial_tls;
R
Rich Felker 已提交
1166 1167

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

	decode_vec(auxv, aux, AUX_CNT);

1177 1178
	/* 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 已提交
1179
	  || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
1180
		env_path = 0;
R
Rich Felker 已提交
1181
		env_preload = 0;
1182
		libc.secure = 1;
1183
	}
1184
	libc.page_size = aux[AT_PAGESZ];
1185
	libc.auxv = auxv;
1186

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

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

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

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

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

T
Timo Teräs 已提交
1330
#ifndef DYNAMIC_IS_RO
R
Rich Felker 已提交
1331 1332 1333
	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 已提交
1334 1335
#endif

R
Rich Felker 已提交
1336 1337 1338 1339
	/* 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 已提交
1340 1341

	update_tls_size();
1342 1343 1344
	if (libc.tls_size > sizeof builtin_tls) {
		initial_tls = calloc(libc.tls_size, 1);
		if (!initial_tls) {
1345
			dprintf(2, "%s: Error getting %zu bytes thread-local storage: %m\n",
1346
				argv[0], libc.tls_size);
1347 1348
			_exit(127);
		}
1349 1350 1351 1352 1353 1354
	} else {
		initial_tls = builtin_tls;
	}
	if (__init_tp(__copy_tls(initial_tls)) < 0 && tls_cnt) {
		dprintf(2, "%s: Thread-local storage not supported by kernel.\n", argv[0]);
		_exit(127);
1355
	}
1356
	static_tls_cnt = tls_cnt;
1357

1358
	if (ldso_fail) _exit(127);
1359 1360
	if (ldd_mode) _exit(0);

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

1366 1367 1368
	debug.ver = 1;
	debug.bp = _dl_debug_state;
	debug.head = head;
R
Rich Felker 已提交
1369
	debug.base = ldso.base;
1370 1371 1372
	debug.state = 0;
	_dl_debug_state();

1373
	__init_libc(envp, argv[0]);
1374
	atexit(do_fini);
1375
	errno = 0;
1376
	do_init_fini(tail);
1377

R
Rich Felker 已提交
1378 1379
	CRTJMP((void *)aux[AT_ENTRY], argv-1);
	for(;;);
1380 1381
}

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

	if (!file) return head;

1392
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
1393
	pthread_rwlock_wrlock(&lock);
1394
	__inhibit_ptc();
1395

1396 1397
	p = 0;
	orig_tls_cnt = tls_cnt;
R
Rich Felker 已提交
1398 1399
	orig_tls_offset = tls_offset;
	orig_tls_align = tls_align;
R
Rich Felker 已提交
1400
	orig_tail = tail;
1401
	noload = mode & RTLD_NOLOAD;
R
Rich Felker 已提交
1402

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

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

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

	if (mode & RTLD_GLOBAL) {
R
Rich Felker 已提交
1456
		if (p->deps) for (i=0; p->deps[i]; i++)
1457 1458 1459 1460
			p->deps[i]->global = 1;
		p->global = 1;
	}

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

1473
static int invalid_dso_handle(void *h)
1474 1475 1476 1477 1478 1479 1480 1481
{
	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;
}

1482 1483
void *__tls_get_addr(size_t *);

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

1535
int __dladdr(const void *addr, Dl_info *info)
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
{
	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 已提交
1560
		for (i = nsym = 0; i < p->ghashtab[0]; i++) {
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572
			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++) {
1573
		if (sym->st_value
1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
		 && (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;
}

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

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;
}
1630
#else
1631
static int invalid_dso_handle(void *h)
1632 1633 1634 1635 1636
{
	snprintf(errbuf, sizeof errbuf, "Invalid library handle %p", (void *)h);
	errflag = 1;
	return 1;
}
1637 1638
void *dlopen(const char *file, int mode)
{
1639 1640
	strcpy(errbuf, "Dynamic loading not supported");
	errflag = 1;
1641 1642
	return 0;
}
1643
void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra)
1644
{
1645 1646
	errflag = 1;
	snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
1647 1648
	return 0;
}
1649
int __dladdr (const void *addr, Dl_info *info)
1650 1651 1652
{
	return 0;
}
1653
#endif
1654

R
Rich Felker 已提交
1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
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;
}

1667 1668
char *dlerror()
{
R
Rich Felker 已提交
1669 1670
	if (!errflag) return 0;
	errflag = 0;
1671
	return errbuf;
1672 1673 1674 1675
}

int dlclose(void *p)
{
1676
	return invalid_dso_handle(p);
1677
}