dynlink.c 18.6 KB
Newer Older
R
Rich Felker 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <elf.h>
#include <sys/mman.h>
#include <limits.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <elf.h>
R
Rich Felker 已提交
15
#include <setjmp.h>
16
#include <pthread.h>
R
Rich Felker 已提交
17
#include <ctype.h>
18
#include <dlfcn.h>
R
Rich Felker 已提交
19

R
Rich Felker 已提交
20
static int errflag;
21
static char errbuf[128];
R
Rich Felker 已提交
22 23 24

#ifdef __PIC__

R
Rich Felker 已提交
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
#include "reloc.h"

#if ULONG_MAX == 0xffffffff
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Sym Sym;
#define R_TYPE(x) ((x)&255)
#define R_SYM(x) ((x)>>8)
#else
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Sym Sym;
#define R_TYPE(x) ((x)&0xffffffff)
#define R_SYM(x) ((x)>>32)
#endif

struct dso
{
	struct dso *next, *prev;
	int refcnt;
	size_t *dynv;
	Sym *syms;
47
	uint32_t *hashtab;
R
Rich Felker 已提交
48 49 50 51 52 53
	char *strings;
	unsigned char *base;
	unsigned char *map;
	size_t map_len;
	dev_t dev;
	ino_t ino;
54 55 56
	char global;
	char relocated;
	char constructed;
57
	struct dso **deps;
R
Rich Felker 已提交
58 59
	char *name;
	char buf[];
R
Rich Felker 已提交
60 61 62
};

static struct dso *head, *tail, *libc;
63
static char *env_path, *sys_path, *r_path;
64
static int rtld_used;
R
Rich Felker 已提交
65 66
static int runtime;
static jmp_buf rtld_fail;
67
static pthread_rwlock_t lock;
R
Rich Felker 已提交
68

R
Rich Felker 已提交
69
#define AUX_CNT 24
R
Rich Felker 已提交
70 71 72 73 74 75 76 77 78 79 80
#define DYN_CNT 34

static void decode_vec(size_t *v, size_t *a, size_t cnt)
{
	memset(a, 0, cnt*sizeof(size_t));
	for (; v[0]; v+=2) if (v[0]<cnt) {
		a[0] |= 1ULL<<v[0];
		a[v[0]] = v[1];
	}
}

81
static uint32_t hash(const char *s0)
R
Rich Felker 已提交
82
{
83
	const unsigned char *s = (void *)s0;
R
Rich Felker 已提交
84 85 86 87 88 89 90 91
	uint_fast32_t h = 0;
	while (*s) {
		h = 16*h + *s++;
		h ^= h>>24 & 0xf0;
	}
	return h & 0xfffffff;
}

92
static Sym *lookup(const char *s, uint32_t h, Sym *syms, uint32_t *hashtab, char *strings)
R
Rich Felker 已提交
93 94 95 96 97 98 99 100 101 102
{
	size_t i;
	for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) {
		if (!strcmp(s, strings+syms[i].st_name))
			return syms+i;
	}
	return 0;
}

#define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON)
103
#define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK)
R
Rich Felker 已提交
104 105 106 107

static void *find_sym(struct dso *dso, const char *s, int need_def)
{
	uint32_t h = hash(s);
108
	void *def = 0;
109 110
	if (h==0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1;
	if (h==0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1;
R
Rich Felker 已提交
111
	for (; dso; dso=dso->next) {
112 113 114
		Sym *sym;
		if (!dso->global) continue;
		sym = lookup(s, h, dso->syms, dso->hashtab, dso->strings);
R
Rich Felker 已提交
115
		if (sym && (!need_def || sym->st_shndx) && sym->st_value
116 117
		 && (1<<(sym->st_info&0xf) & OK_TYPES)
		 && (1<<(sym->st_info>>4) & OK_BINDS)) {
118
			if (def && sym->st_info>>4 == STB_WEAK) continue;
119 120 121
			def = dso->base + sym->st_value;
			if (sym->st_info>>4 == STB_GLOBAL) break;
		}
R
Rich Felker 已提交
122
	}
123
	return def;
R
Rich Felker 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
}

static void do_relocs(unsigned char *base, size_t *rel, size_t rel_size, size_t stride, Sym *syms, char *strings, struct dso *dso)
{
	Sym *sym;
	const char *name;
	size_t sym_val, sym_size;
	size_t *reloc_addr;
	void *ctx;
	int type;
	int sym_index;

	for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) {
		reloc_addr = (void *)(base + rel[0]);
		type = R_TYPE(rel[1]);
		sym_index = R_SYM(rel[1]);
		if (sym_index) {
			sym = syms + sym_index;
			name = strings + sym->st_name;
			ctx = IS_COPY(type) ? dso->next : dso;
144
			sym_val = (size_t)find_sym(ctx, name, IS_PLT(type));
R
Rich Felker 已提交
145
			if (!sym_val && sym->st_info>>4 != STB_WEAK) {
146 147 148
				snprintf(errbuf, sizeof errbuf,
					"Error relocating %s: %s: symbol not found",
					dso->name, name);
R
Rich Felker 已提交
149
				if (runtime) longjmp(rtld_fail, 1);
150
				dprintf(2, "%s\n", errbuf);
R
Rich Felker 已提交
151 152
				_exit(127);
			}
R
Rich Felker 已提交
153 154 155 156 157 158
			sym_size = sym->st_size;
		}
		do_single_reloc(reloc_addr, type, sym_val, sym_size, base, rel[2]);
	}
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
/* 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. */

static void reclaim(unsigned char *base, size_t start, size_t end)
{
	size_t *a, *z;
	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;
	a = (size_t *)(base + start);
	z = (size_t *)(base + end);
	a[-2] = 1;
	a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1;
	z[1] = 1;
	free(a);
}

static void reclaim_gaps(unsigned char *base, Phdr *ph, size_t phent, size_t phcnt)
{
	for (; phcnt--; ph=(void *)((char *)ph+phent)) {
		if (ph->p_type!=PT_LOAD) continue;
		if ((ph->p_flags&(PF_R|PF_W))!=(PF_R|PF_W)) continue;
		reclaim(base, ph->p_vaddr & -PAGE_SIZE, ph->p_vaddr);
		reclaim(base, ph->p_vaddr+ph->p_memsz,
			ph->p_vaddr+ph->p_memsz+PAGE_SIZE-1 & -PAGE_SIZE);
	}
}

R
Rich Felker 已提交
190 191
static void *map_library(int fd, size_t *lenp, unsigned char **basep, size_t *dynp)
{
192
	Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
R
Rich Felker 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205
	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;
	Phdr *ph;
	unsigned prot;
	unsigned char *map, *base;
	size_t dyn;
	size_t i;

	ssize_t l = read(fd, buf, sizeof buf);
	if (l<sizeof *eh) return 0;
206
	eh = buf;
R
Rich Felker 已提交
207 208 209
	phsize = eh->e_phentsize * eh->e_phnum;
	if (phsize + sizeof *eh > l) return 0;
	if (eh->e_phoff + phsize > l) {
210
		l = pread(fd, buf+1, phsize, eh->e_phoff);
R
Rich Felker 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
		if (l != phsize) return 0;
		eh->e_phoff = sizeof *eh;
	}
	ph = (void *)((char *)buf + eh->e_phoff);
	for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
		if (ph->p_type == PT_DYNAMIC)
			dyn = ph->p_vaddr;
		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;
		}
	}
	if (!dyn) return 0;
	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. */
240
	map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
R
Rich Felker 已提交
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
	if (map==MAP_FAILED) return 0;
	base = map - addr_min;
	ph = (void *)((char *)buf + eh->e_phoff);
	for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) {
		if (ph->p_type != PT_LOAD) continue;
		/* 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));
		if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) {
			munmap(map, map_len);
			return 0;
		}
		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);
			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) {
				munmap(map, map_len);
				return 0;
			}
		}
	}
R
Rich Felker 已提交
268 269 270 271 272
	for (i=0; ((size_t *)(base+dyn))[i]; i+=2)
		if (((size_t *)(base+dyn))[i]==DT_TEXTREL) {
			mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC);
			break;
		}
273 274
	if (!runtime) reclaim_gaps(base, (void *)((char *)buf + eh->e_phoff),
		eh->e_phentsize, eh->e_phnum);
R
Rich Felker 已提交
275 276 277 278 279 280
	*lenp = map_len;
	*basep = base;
	*dynp = dyn;
	return map;
}

281 282 283
static int path_open(const char *name, const char *search)
{
	char buf[2*NAME_MAX+2];
284
	const char *s=search, *z;
285
	int l, fd;
286 287 288
	for (;;) {
		while (*s==':') s++;
		if (!*s) return -1;
289 290 291 292
		z = strchr(s, ':');
		l = z ? z-s : strlen(s);
		snprintf(buf, sizeof buf, "%.*s/%s", l, s, name);
		if ((fd = open(buf, O_RDONLY))>=0) return fd;
293
		s += l;
294 295 296
	}
}

297 298 299 300 301 302 303 304 305
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->hashtab = (void *)(p->base + dyn[DT_HASH]);
	p->strings = (void *)(p->base + dyn[DT_STRTAB]);
}

R
Rich Felker 已提交
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
static struct dso *load_library(const char *name)
{
	unsigned char *base, *map;
	size_t dyno, map_len;
	struct dso *p;
	int fd;
	struct stat st;

	/* 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;
			for (rp=reserved; *rp && memcmp(name+3, rp, l-3); rp+=strlen(rp)+1);
			if (*rp) {
				if (!libc->prev) {
					tail->next = libc;
					libc->prev = tail;
326
					tail = libc->next ? libc->next : libc;
R
Rich Felker 已提交
327 328 329 330 331 332 333 334 335 336 337 338
				}
				return libc;
			}
		}
	}
	/* Search for the name to see if it's already loaded */
	for (p=head->next; p; p=p->next) {
		if (!strcmp(p->name, name)) {
			p->refcnt++;
			return p;
		}
	}
339
	if (strchr(name, '/')) {
R
Rich Felker 已提交
340 341
		fd = open(name, O_RDONLY);
	} else {
342
		if (strlen(name) > NAME_MAX) return 0;
343
		fd = -1;
344 345
		if (r_path) fd = path_open(name, r_path);
		if (fd < 0 && env_path) fd = path_open(name, env_path);
346 347 348 349 350 351 352 353 354 355 356
		if (fd < 0) {
			if (!sys_path) {
				FILE *f = fopen(ETC_LDSO_PATH, "r");
				if (f) {
					if (getline(&sys_path, (size_t[1]){0}, f) > 0)
						sys_path[strlen(sys_path)-1]=0;
					fclose(f);
				}
			}
			if (sys_path) fd = path_open(name, sys_path);
			else fd = path_open(name, "/lib:/usr/local/lib:/usr/lib");
R
Rich Felker 已提交
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
		}
	}
	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) {
			close(fd);
			p->refcnt++;
			return p;
		}
	}
	map = map_library(fd, &map_len, &base, &dyno);
	close(fd);
	if (!map) return 0;
	p = calloc(1, sizeof *p + strlen(name) + 1);
	if (!p) {
		munmap(map, map_len);
		return 0;
	}

	p->map = map;
	p->map_len = map_len;
	p->base = base;
	p->dynv = (void *)(base + dyno);
384
	decode_dyn(p);
R
Rich Felker 已提交
385 386 387 388

	p->dev = st.st_dev;
	p->ino = st.st_ino;
	p->refcnt = 1;
R
Rich Felker 已提交
389
	p->name = p->buf;
R
Rich Felker 已提交
390 391 392 393 394 395 396 397 398 399 400
	strcpy(p->name, name);

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

	return p;
}

static void load_deps(struct dso *p)
{
401 402
	size_t i, ndeps=0;
	struct dso ***deps = &p->deps, **tmp, *dep;
R
Rich Felker 已提交
403
	for (; p; p=p->next) {
404 405 406 407
		for (i=0; p->dynv[i]; i+=2) {
			if (p->dynv[i] != DT_RPATH) continue;
			r_path = (void *)(p->strings + p->dynv[i+1]);
		}
R
Rich Felker 已提交
408 409
		for (i=0; p->dynv[i]; i+=2) {
			if (p->dynv[i] != DT_NEEDED) continue;
410 411
			dep = load_library(p->strings + p->dynv[i+1]);
			if (!dep) {
412 413
				snprintf(errbuf, sizeof errbuf,
					"Error loading shared library %s: %m (needed by %s)",
R
Rich Felker 已提交
414
					p->strings + p->dynv[i+1], p->name);
415 416
				if (runtime) longjmp(rtld_fail, 1);
				dprintf(2, "%s\n", errbuf);
R
Rich Felker 已提交
417 418
				_exit(127);
			}
419 420 421 422 423 424 425
			if (runtime) {
				tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2));
				if (!tmp) longjmp(rtld_fail, 1);
				tmp[ndeps++] = dep;
				tmp[ndeps] = 0;
				*deps = tmp;
			}
R
Rich Felker 已提交
426
		}
427
		r_path = 0;
R
Rich Felker 已提交
428 429 430
	}
}

R
Rich Felker 已提交
431 432 433 434 435 436 437 438 439 440 441 442 443 444
static void load_preload(char *s)
{
	int tmp;
	char *z;
	for (z=s; *z; s=z) {
		for (   ; *s && isspace(*s); s++);
		for (z=s; *z && !isspace(*z); z++);
		tmp = *z;
		*z = 0;
		load_library(s);
		*z = tmp;
	}
}

445 446 447 448 449
static void make_global(struct dso *p)
{
	for (; p; p=p->next) p->global = 1;
}

R
Rich Felker 已提交
450 451 452 453 454 455 456
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);
		do_relocs(p->base, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ],
457
			2+(dyn[DT_PLTREL]==DT_RELA), p->syms, p->strings, head);
R
Rich Felker 已提交
458
		do_relocs(p->base, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ],
459
			2, p->syms, p->strings, head);
R
Rich Felker 已提交
460
		do_relocs(p->base, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ],
461
			3, p->syms, p->strings, head);
462
		p->relocated = 1;
R
Rich Felker 已提交
463 464 465
	}
}

466 467 468 469 470 471 472 473 474 475
static void free_all(struct dso *p)
{
	struct dso *n;
	while (p) {
		n = p->next;
		if (p->map) free(p);
		p = n;
	}
}

476 477 478 479 480 481 482 483
static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride)
{
	for (; cnt--; ph = (void *)((char *)ph + stride))
		if (ph->p_type == PT_DYNAMIC)
			return ph->p_vaddr;
	return 0;
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497
static void do_init_fini(struct dso *p)
{
	size_t dyn[DYN_CNT] = {0};
	for (; p; p=p->prev) {
		if (p->constructed) return;
		decode_vec(p->dynv, dyn, DYN_CNT);
		if (dyn[0] & (1<<DT_FINI))
			atexit((void (*)(void))(p->base + dyn[DT_FINI]));
		if (dyn[0] & (1<<DT_INIT))
			((void (*)(void))(p->base + dyn[DT_INIT]))();
		p->constructed = 1;
	}
}

498
void *__dynlink(int argc, char **argv)
R
Rich Felker 已提交
499 500 501 502
{
	size_t *auxv, aux[AUX_CNT] = {0};
	size_t i;
	Phdr *phdr;
503
	Ehdr *ehdr;
504
	static struct dso builtin_dsos[3];
R
Rich Felker 已提交
505 506
	struct dso *const app = builtin_dsos+0;
	struct dso *const lib = builtin_dsos+1;
507
	struct dso *const vdso = builtin_dsos+2;
R
Rich Felker 已提交
508
	char *env_preload=0;
R
Rich Felker 已提交
509 510

	/* Find aux vector just past environ[] */
511 512 513
	for (i=argc+1; argv[i]; i++)
		if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16))
			env_path = argv[i]+16;
R
Rich Felker 已提交
514 515
		else if (!memcmp(argv[i], "LD_PRELOAD=", 11))
			env_preload = argv[i]+11;
R
Rich Felker 已提交
516 517 518 519
	auxv = (void *)(argv+i+1);

	decode_vec(auxv, aux, AUX_CNT);

520 521
	/* 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 已提交
522
	  || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) {
523
		env_path = 0;
R
Rich Felker 已提交
524
		env_preload = 0;
525 526
	}

527 528 529 530 531 532 533 534 535 536 537
	/* The dynamic linker load address is passed by the kernel
	 * in the AUX vector, so this is easy. */
	lib->base = (void *)aux[AT_BASE];
	lib->name = "libc.so";
	lib->global = 1;
	ehdr = (void *)lib->base;
	lib->dynv = (void *)(lib->base + find_dyn(
		(void *)(aux[AT_BASE]+ehdr->e_phoff),
		ehdr->e_phnum, ehdr->e_phentsize));
	decode_dyn(lib);

538
	/* Find load address of the main program, via AT_PHDR vs PT_PHDR. */
539
	app->base = 0;
540 541 542 543 544
	phdr = (void *)aux[AT_PHDR];
	for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) {
		if (phdr->p_type == PT_PHDR)
			app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr);
	}
545 546
	app->name = argv[0];
	app->global = 1;
547
	app->constructed = 1;
548 549 550 551 552
	app->dynv = (void *)(app->base + find_dyn(
		(void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT]));
	decode_dyn(app);

	/* Attach to vdso, if provided by the kernel */
553
	for (i=0; auxv[i]; i+=2) {
554 555
		size_t vdso_base = auxv[i+1];
		if (auxv[i] != AT_SYSINFO_EHDR) continue;
556 557 558 559 560 561 562 563 564
		ehdr = (void *)vdso_base;
		phdr = (void *)(vdso_base + ehdr->e_phoff);
		for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) {
			if (phdr->p_type == PT_DYNAMIC)
				vdso->dynv = (void *)(vdso_base + phdr->p_offset);
			if (phdr->p_type == PT_LOAD)
				vdso->base = (void *)(vdso_base - phdr->p_vaddr + phdr->p_offset);
		}
		vdso->name = "linux-gate.so.1";
565
		vdso->global = 1;
566
		decode_dyn(vdso);
567 568
		vdso->prev = lib;
		lib->next = vdso;
569
		break;
570 571
	}

572 573 574 575 576 577 578 579 580
	/* Initial dso chain consists only of the app. We temporarily
	 * append the dynamic linker/libc so we can relocate it, then
	 * restore the initial chain in preparation for loading third
	 * party libraries (preload/needed). */
	head = tail = app;
	libc = lib;
	app->next = lib;
	reloc_all(lib);
	app->next = 0;
R
Rich Felker 已提交
581

582
	/* PAST THIS POINT, ALL LIBC INTERFACES ARE FULLY USABLE. */
R
Rich Felker 已提交
583

584
	/* Donate unused parts of app and library mapping to malloc */
R
Rich Felker 已提交
585 586 587
	reclaim_gaps(app->base, (void *)aux[AT_PHDR], aux[AT_PHENT], aux[AT_PHNUM]);
	ehdr = (void *)lib->base;
	reclaim_gaps(lib->base, (void *)(lib->base+ehdr->e_phoff),
588 589
		ehdr->e_phentsize, ehdr->e_phnum);

590
	/* Load preload/needed libraries, add their symbols to the global
591 592 593
	 * namespace, and perform all remaining relocations. The main
	 * program must be relocated LAST since it may contain copy
	 * relocations which depend on libraries' relocations. */
R
Rich Felker 已提交
594
	if (env_preload) load_preload(env_preload);
595 596
	load_deps(app);
	make_global(app);
597
	reloc_all(app->next);
598 599 600 601 602 603
	reloc_all(app);

	/* Switch to runtime mode: any further failures in the dynamic
	 * linker are a reportable failure rather than a fatal startup
	 * error. If the dynamic loader (dlopen) will not be used, free
	 * all memory used by the dynamic linker. */
R
Rich Felker 已提交
604
	runtime = 1;
605 606 607

	do_init_fini(tail);

R
Rich Felker 已提交
608
	if (!rtld_used) {
609 610
		free_all(head);
		free(sys_path);
R
Rich Felker 已提交
611
		reclaim((void *)builtin_dsos, 0, sizeof builtin_dsos);
612
	}
613

R
Rich Felker 已提交
614 615 616
	errno = 0;
	return (void *)aux[AT_ENTRY];
}
617 618 619

void *dlopen(const char *file, int mode)
{
620
	struct dso *volatile p, *orig_tail = tail, *next;
621
	size_t i;
622
	int cs;
623 624 625

	if (!file) return head;

626
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
627 628 629 630
	pthread_rwlock_wrlock(&lock);

	if (setjmp(rtld_fail)) {
		/* Clean up anything new that was (partially) loaded */
631 632 633
		if (p->deps) for (i=0; p->deps[i]; i++)
			if (p->deps[i]->global < 0)
				p->deps[i]->global = 0;
634 635 636 637 638 639 640 641
		for (p=orig_tail->next; p; p=next) {
			next = p->next;
			munmap(p->map, p->map_len);
			free(p->deps);
			free(p);
		}
		tail = orig_tail;
		tail->next = 0;
642
		p = 0;
643 644
		errflag = 1;
		goto end;
R
Rich Felker 已提交
645 646 647
	} else p = load_library(file);

	if (!p) {
648 649
		snprintf(errbuf, sizeof errbuf,
			"Error loading shared library %s: %m", file);
R
Rich Felker 已提交
650
		errflag = 1;
651
		goto end;
652 653 654 655 656
	}

	/* First load handling */
	if (!p->deps) {
		load_deps(p);
R
Rich Felker 已提交
657
		if (p->deps) for (i=0; p->deps[i]; i++)
658 659 660
			if (!p->deps[i]->global)
				p->deps[i]->global = -1;
		if (!p->global) p->global = -1;
661
		reloc_all(p);
R
Rich Felker 已提交
662
		if (p->deps) for (i=0; p->deps[i]; i++)
663 664 665
			if (p->deps[i]->global < 0)
				p->deps[i]->global = 0;
		if (p->global < 0) p->global = 0;
666 667 668
	}

	if (mode & RTLD_GLOBAL) {
R
Rich Felker 已提交
669
		if (p->deps) for (i=0; p->deps[i]; i++)
670 671 672 673
			p->deps[i]->global = 1;
		p->global = 1;
	}

674
	do_init_fini(tail);
675
end:
676
	pthread_rwlock_unlock(&lock);
677
	pthread_setcancelstate(cs, 0);
678 679 680
	return p;
}

R
Rich Felker 已提交
681
static void *do_dlsym(struct dso *p, const char *s, void *ra)
682 683 684 685
{
	size_t i;
	uint32_t h;
	Sym *sym;
R
Rich Felker 已提交
686 687 688 689 690
	if (p == RTLD_NEXT) {
		for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next);
		if (!p) p=head;
		p=p->next;
	}
R
Rich Felker 已提交
691 692 693 694 695
	if (p == head || p == RTLD_DEFAULT) {
		void *res = find_sym(head, s, 0);
		if (!res) errflag = 1;
		return res;
	}
696 697 698 699 700 701 702 703 704 705
	h = hash(s);
	sym = lookup(s, h, p->syms, p->hashtab, p->strings);
	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++) {
		sym = lookup(s, h, p->deps[i]->syms,
			p->deps[i]->hashtab, p->deps[i]->strings);
		if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES))
			return p->deps[i]->base + sym->st_value;
	}
R
Rich Felker 已提交
706
	errflag = 1;
707
	snprintf(errbuf, sizeof errbuf, "Symbol not found: %s", s);
708 709 710
	return 0;
}

R
Rich Felker 已提交
711
void *__dlsym(void *p, const char *s, void *ra)
712 713 714
{
	void *res;
	pthread_rwlock_rdlock(&lock);
R
Rich Felker 已提交
715
	res = do_dlsym(p, s, ra);
716 717 718
	pthread_rwlock_unlock(&lock);
	return res;
}
719 720 721 722 723 724 725 726 727 728
#else
void *dlopen(const char *file, int mode)
{
	return 0;
}
void *__dlsym(void *p, const char *s, void *ra)
{
	return 0;
}
#endif
729 730 731

char *dlerror()
{
R
Rich Felker 已提交
732 733
	if (!errflag) return 0;
	errflag = 0;
734
	return errbuf;
735 736 737 738 739 740
}

int dlclose(void *p)
{
	return 0;
}