Annotation of src/libexec/ld.elf_so/map_object.c, Revision 1.44.2.3
1.44.2.2 tls 1: /* $NetBSD$ */
1.1 cgd 2:
3: /*
4: * Copyright 1996 John D. Polstra.
5: * Copyright 1996 Matt Thomas <matt@3am-software.com>
1.24 mycroft 6: * Copyright 2002 Charles M. Hannum <root@ihack.net>
1.1 cgd 7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by John Polstra.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
1.31 skrll 35: #include <sys/cdefs.h>
36: #ifndef lint
1.44.2.2 tls 37: __RCSID("$NetBSD$");
1.31 skrll 38: #endif /* not lint */
39:
1.1 cgd 40: #include <errno.h>
41: #include <stddef.h>
1.10 mycroft 42: #include <stdlib.h>
1.1 cgd 43: #include <string.h>
44: #include <unistd.h>
1.10 mycroft 45: #include <sys/stat.h>
1.1 cgd 46: #include <sys/types.h>
47: #include <sys/mman.h>
48:
1.41 skrll 49: #include "debug.h"
1.1 cgd 50: #include "rtld.h"
1.7 hannken 51:
1.30 skrll 52: static int protflags(int); /* Elf flags -> mmap protection */
1.1 cgd 53:
1.41 skrll 54: #define EA_UNDEF (~(Elf_Addr)0)
55:
1.1 cgd 56: /*
57: * Map a shared object into memory. The argument is a file descriptor,
58: * which must be open on the object and positioned at its beginning.
59: *
60: * The return value is a pointer to a newly-allocated Obj_Entry structure
61: * for the shared object. Returns NULL on failure.
62: */
63: Obj_Entry *
1.34 christos 64: _rtld_map_object(const char *path, int fd, const struct stat *sb)
1.1 cgd 65: {
1.18 junyoung 66: Obj_Entry *obj;
67: Elf_Ehdr *ehdr;
68: Elf_Phdr *phdr;
1.42 joerg 69: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
70: Elf_Phdr *phtls;
71: #endif
1.41 skrll 72: size_t phsize;
1.18 junyoung 73: Elf_Phdr *phlimit;
74: Elf_Phdr *segs[2];
75: int nsegs;
1.22 mycroft 76: caddr_t mapbase = MAP_FAILED;
1.32 lukem 77: size_t mapsize = 0;
1.27 matt 78: int mapflags;
1.18 junyoung 79: Elf_Off base_offset;
1.28 taca 80: #ifdef MAP_ALIGNED
1.27 matt 81: Elf_Addr base_alignment;
1.28 taca 82: #endif
1.18 junyoung 83: Elf_Addr base_vaddr;
84: Elf_Addr base_vlimit;
85: Elf_Addr text_vlimit;
1.22 mycroft 86: int text_flags;
1.18 junyoung 87: caddr_t base_addr;
88: Elf_Off data_offset;
89: Elf_Addr data_vaddr;
90: Elf_Addr data_vlimit;
1.22 mycroft 91: int data_flags;
1.18 junyoung 92: caddr_t data_addr;
1.42 joerg 93: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
94: Elf_Addr tls_vaddr = 0; /* Noise GCC */
95: #endif
1.41 skrll 96: Elf_Addr phdr_vaddr;
97: size_t phdr_memsz;
1.18 junyoung 98: caddr_t gap_addr;
99: size_t gap_size;
1.41 skrll 100: int i;
1.1 cgd 101: #ifdef RTLD_LOADER
1.18 junyoung 102: Elf_Addr clear_vaddr;
103: caddr_t clear_addr;
104: size_t nclear;
1.1 cgd 105: #endif
1.26 fvdl 106:
1.38 christos 107: if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
1.44.2.1 tls 108: _rtld_error("%s: not ELF file (too short)", path);
1.26 fvdl 109: return NULL;
110: }
1.1 cgd 111:
1.22 mycroft 112: obj = _rtld_obj_new();
1.34 christos 113: obj->path = xstrdup(path);
1.25 junyoung 114: obj->pathlen = strlen(path);
1.22 mycroft 115: if (sb != NULL) {
116: obj->dev = sb->st_dev;
117: obj->ino = sb->st_ino;
118: }
119:
1.20 mycroft 120: ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
1.16 mycroft 121: (off_t)0);
1.36 ad 122: obj->ehdr = ehdr;
1.20 mycroft 123: if (ehdr == MAP_FAILED) {
1.4 christos 124: _rtld_error("%s: read error: %s", path, xstrerror(errno));
1.22 mycroft 125: goto bad;
1.4 christos 126: }
127: /* Make sure the file is valid */
1.44.2.1 tls 128: if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0) {
129: _rtld_error("%s: not ELF file (magic number bad)", path);
130: goto bad;
131: }
132: if (ehdr->e_ident[EI_CLASS] != ELFCLASS) {
133: _rtld_error("%s: invalid ELF class %x; expected %x", path,
1.40 skrll 134: ehdr->e_ident[EI_CLASS], ELFCLASS);
1.16 mycroft 135: goto bad;
1.4 christos 136: }
137: /* Elf_e_ident includes class */
1.17 junyoung 138: if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
139: ehdr->e_version != EV_CURRENT ||
140: ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
1.16 mycroft 141: _rtld_error("%s: unsupported file version", path);
142: goto bad;
143: }
1.17 junyoung 144: if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
1.16 mycroft 145: _rtld_error("%s: unsupported file type", path);
146: goto bad;
1.4 christos 147: }
1.17 junyoung 148: switch (ehdr->e_machine) {
1.4 christos 149: ELFDEFNNAME(MACHDEP_ID_CASES)
150: default:
1.16 mycroft 151: _rtld_error("%s: unsupported machine", path);
152: goto bad;
1.4 christos 153: }
154:
155: /*
156: * We rely on the program header being in the first page. This is
157: * not strictly required by the ABI specification, but it seems to
158: * always true in practice. And, it simplifies things considerably.
159: */
1.17 junyoung 160: assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
1.19 junyoung 161: assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
162: _rtld_pagesz);
1.4 christos 163:
164: /*
165: * Scan the program header entries, and save key information.
166: *
167: * We rely on there being exactly two load segments, text and data,
168: * in that order.
169: */
1.17 junyoung 170: phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
1.42 joerg 171: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
172: phtls = NULL;
173: #endif
1.41 skrll 174: phsize = ehdr->e_phnum * sizeof(phdr[0]);
175: obj->phdr = NULL;
176: phdr_vaddr = EA_UNDEF;
177: phdr_memsz = 0;
1.17 junyoung 178: phlimit = phdr + ehdr->e_phnum;
1.4 christos 179: nsegs = 0;
180: while (phdr < phlimit) {
181: switch (phdr->p_type) {
1.10 mycroft 182: case PT_INTERP:
1.37 mrg 183: obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
1.41 skrll 184: dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
1.10 mycroft 185: break;
1.1 cgd 186:
1.8 kleink 187: case PT_LOAD:
1.12 mycroft 188: if (nsegs < 2)
189: segs[nsegs] = phdr;
1.4 christos 190: ++nsegs;
1.44 martin 191:
192: dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_LOAD",
1.43 christos 193: (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
1.4 christos 194: break;
195:
1.41 skrll 196: case PT_PHDR:
197: phdr_vaddr = phdr->p_vaddr;
198: phdr_memsz = phdr->p_memsz;
1.44 martin 199: dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_PHDR",
1.43 christos 200: (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
1.41 skrll 201: break;
1.44.2.2 tls 202:
1.8 kleink 203: case PT_DYNAMIC:
1.37 mrg 204: obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
1.44 martin 205: dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_DYNAMIC",
1.43 christos 206: (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
1.4 christos 207: break;
1.42 joerg 208:
209: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
210: case PT_TLS:
211: phtls = phdr;
1.44 martin 212: dbg(("%s: %s %p phsize %" PRImemsz, obj->path, "PT_TLS",
1.43 christos 213: (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
1.42 joerg 214: break;
215: #endif
1.44.2.2 tls 216: #ifdef __ARM_EABI__
217: case PT_ARM_EXIDX:
218: obj->exidx_start = (void *)(uintptr_t)phdr->p_vaddr;
219: obj->exidx_sz = phdr->p_memsz;
220: break;
221: #endif
1.4 christos 222: }
1.1 cgd 223:
1.4 christos 224: ++phdr;
225: }
1.41 skrll 226: phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
1.37 mrg 227: obj->entry = (void *)(uintptr_t)ehdr->e_entry;
1.22 mycroft 228: if (!obj->dynamic) {
1.12 mycroft 229: _rtld_error("%s: not dynamically linked", path);
1.16 mycroft 230: goto bad;
1.12 mycroft 231: }
232: if (nsegs != 2) {
233: _rtld_error("%s: wrong number of segments (%d != 2)", path,
234: nsegs);
1.16 mycroft 235: goto bad;
1.4 christos 236: }
1.1 cgd 237:
1.4 christos 238: /*
1.11 chs 239: * Map the entire address space of the object as a file
1.5 thorpej 240: * region to stake out our contiguous region and establish a
1.11 chs 241: * base for relocation. We use a file mapping so that
242: * the kernel will give us whatever alignment is appropriate
243: * for the platform we're running on.
1.5 thorpej 244: *
1.11 chs 245: * We map it using the text protection, map the data segment
246: * into the right place, then map an anon segment for the bss
247: * and unmap the gaps left by padding to alignment.
1.5 thorpej 248: */
1.11 chs 249:
1.27 matt 250: #ifdef MAP_ALIGNED
251: base_alignment = segs[0]->p_align;
252: #endif
1.4 christos 253: base_offset = round_down(segs[0]->p_offset);
254: base_vaddr = round_down(segs[0]->p_vaddr);
255: base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
1.11 chs 256: text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
1.22 mycroft 257: text_flags = protflags(segs[0]->p_flags);
258: data_offset = round_down(segs[1]->p_offset);
259: data_vaddr = round_down(segs[1]->p_vaddr);
260: data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
261: data_flags = protflags(segs[1]->p_flags);
1.23 mycroft 262: #ifdef RTLD_LOADER
1.22 mycroft 263: clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
1.23 mycroft 264: #endif
1.22 mycroft 265:
266: obj->textsize = text_vlimit - base_vaddr;
267: obj->vaddrbase = base_vaddr;
268: obj->isdynamic = ehdr->e_type == ET_DYN;
269:
1.42 joerg 270: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
271: if (phtls != NULL) {
272: ++_rtld_tls_dtv_generation;
273: obj->tlsindex = ++_rtld_tls_max_index;
274: obj->tlssize = phtls->p_memsz;
275: obj->tlsalign = phtls->p_align;
276: obj->tlsinitsize = phtls->p_filesz;
277: tls_vaddr = phtls->p_vaddr;
278: }
279: #endif
280:
1.41 skrll 281: obj->phdr_loaded = false;
282: for (i = 0; i < nsegs; i++) {
283: if (phdr_vaddr != EA_UNDEF &&
284: segs[i]->p_vaddr <= phdr_vaddr &&
285: segs[i]->p_memsz >= phdr_memsz) {
286: obj->phdr_loaded = true;
287: break;
288: }
289: if (segs[i]->p_offset <= ehdr->e_phoff &&
290: segs[i]->p_memsz >= phsize) {
291: phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
292: phdr_memsz = phsize;
293: obj->phdr_loaded = true;
294: break;
295: }
296: }
297: if (obj->phdr_loaded) {
298: obj->phdr = (void *)(uintptr_t)phdr_vaddr;
299: obj->phsize = phdr_memsz;
300: } else {
301: Elf_Phdr *buf;
302: buf = xmalloc(phsize);
303: if (buf == NULL) {
304: _rtld_error("%s: cannot allocate program header", path);
305: goto bad;
306: }
307: memcpy(buf, phdr, phsize);
308: obj->phdr = buf;
309: obj->phsize = phsize;
310: }
311: dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize,
312: obj->phdr_loaded ? "loaded" : "allocated"));
313:
1.36 ad 314: /* Unmap header if it overlaps the first load section. */
315: if (base_offset < _rtld_pagesz) {
316: munmap(ehdr, _rtld_pagesz);
317: obj->ehdr = MAP_FAILED;
318: }
1.11 chs 319:
1.27 matt 320: /*
321: * Calculate log2 of the base section alignment.
322: */
323: mapflags = 0;
324: #ifdef MAP_ALIGNED
325: if (base_alignment > _rtld_pagesz) {
326: unsigned int log2 = 0;
327: for (; base_alignment > 1; base_alignment >>= 1)
328: log2++;
329: mapflags = MAP_ALIGNED(log2);
330: }
331: #endif
332:
1.1 cgd 333: #ifdef RTLD_LOADER
1.22 mycroft 334: base_addr = obj->isdynamic ? NULL : (caddr_t)base_vaddr;
1.1 cgd 335: #else
1.4 christos 336: base_addr = NULL;
1.1 cgd 337: #endif
1.22 mycroft 338: mapsize = base_vlimit - base_vaddr;
1.27 matt 339: mapbase = mmap(base_addr, mapsize, text_flags,
340: mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
1.5 thorpej 341: if (mapbase == MAP_FAILED) {
1.4 christos 342: _rtld_error("mmap of entire address space failed: %s",
343: xstrerror(errno));
1.16 mycroft 344: goto bad;
1.4 christos 345: }
1.11 chs 346:
1.4 christos 347: /* Overlay the data segment onto the proper region. */
348: data_addr = mapbase + (data_vaddr - base_vaddr);
1.22 mycroft 349: if (mmap(data_addr, data_vlimit - data_vaddr, data_flags,
350: MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) ==
351: MAP_FAILED) {
1.4 christos 352: _rtld_error("mmap of data failed: %s", xstrerror(errno));
1.22 mycroft 353: goto bad;
1.11 chs 354: }
355:
356: /* Overlay the bss segment onto the proper region. */
357: if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
1.22 mycroft 358: data_flags, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) ==
359: MAP_FAILED) {
1.11 chs 360: _rtld_error("mmap of bss failed: %s", xstrerror(errno));
1.22 mycroft 361: goto bad;
1.4 christos 362: }
1.5 thorpej 363:
364: /* Unmap the gap between the text and data. */
1.22 mycroft 365: gap_addr = mapbase + round_up(text_vlimit - base_vaddr);
1.5 thorpej 366: gap_size = data_addr - gap_addr;
1.21 mycroft 367: if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) {
368: _rtld_error("mprotect of text -> data gap failed: %s",
1.5 thorpej 369: xstrerror(errno));
1.22 mycroft 370: goto bad;
1.5 thorpej 371: }
372:
1.1 cgd 373: #ifdef RTLD_LOADER
1.4 christos 374: /* Clear any BSS in the last page of the data segment. */
375: clear_addr = mapbase + (clear_vaddr - base_vaddr);
376: if ((nclear = data_vlimit - clear_vaddr) > 0)
377: memset(clear_addr, 0, nclear);
378:
1.5 thorpej 379: /* Non-file portion of BSS mapped above. */
1.1 cgd 380: #endif
381:
1.42 joerg 382: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
383: if (phtls != NULL)
384: obj->tlsinit = mapbase + tls_vaddr;
385: #endif
386:
1.4 christos 387: obj->mapbase = mapbase;
388: obj->mapsize = mapsize;
389: obj->relocbase = mapbase - base_vaddr;
1.10 mycroft 390:
1.22 mycroft 391: if (obj->dynamic)
1.37 mrg 392: obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic);
1.22 mycroft 393: if (obj->entry)
1.37 mrg 394: obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry);
1.22 mycroft 395: if (obj->interp)
1.37 mrg 396: obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp);
1.41 skrll 397: if (obj->phdr_loaded)
398: obj->phdr = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr);
1.44.2.2 tls 399: #ifdef __ARM_EABI__
400: if (obj->exidx_start)
401: obj->exidx_start = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->exidx_start);
402: #endif
1.22 mycroft 403:
1.10 mycroft 404: return obj;
1.16 mycroft 405:
406: bad:
1.36 ad 407: if (obj->ehdr != MAP_FAILED)
408: munmap(obj->ehdr, _rtld_pagesz);
1.22 mycroft 409: if (mapbase != MAP_FAILED)
410: munmap(mapbase, mapsize);
411: _rtld_obj_free(obj);
1.16 mycroft 412: return NULL;
1.10 mycroft 413: }
414:
415: void
1.30 skrll 416: _rtld_obj_free(Obj_Entry *obj)
1.10 mycroft 417: {
418: Objlist_Entry *elm;
1.44.2.2 tls 419: Name_Entry *entry;
1.10 mycroft 420:
1.42 joerg 421: #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
422: if (obj->tls_done)
423: _rtld_tls_offset_free(obj);
424: #endif
1.35 ad 425: xfree(obj->path);
1.10 mycroft 426: while (obj->needed != NULL) {
427: Needed_Entry *needed = obj->needed;
428: obj->needed = needed->next;
1.35 ad 429: xfree(needed);
1.10 mycroft 430: }
1.44.2.2 tls 431: while ((entry = SIMPLEQ_FIRST(&obj->names)) != NULL) {
432: SIMPLEQ_REMOVE_HEAD(&obj->names, link);
433: xfree(entry);
434: }
1.13 lukem 435: while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) {
436: SIMPLEQ_REMOVE_HEAD(&obj->dldags, link);
1.35 ad 437: xfree(elm);
1.10 mycroft 438: }
1.13 lukem 439: while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) {
440: SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link);
1.35 ad 441: xfree(elm);
1.10 mycroft 442: }
1.41 skrll 443: if (!obj->phdr_loaded)
444: xfree((void *)(uintptr_t)obj->phdr);
1.35 ad 445: xfree(obj);
1.39 skrll 446: #ifdef COMBRELOC
447: _rtld_combreloc_reset(obj);
448: #endif
1.10 mycroft 449: }
450:
451: Obj_Entry *
452: _rtld_obj_new(void)
453: {
454: Obj_Entry *obj;
455:
456: obj = CNEW(Obj_Entry);
1.44.2.2 tls 457: SIMPLEQ_INIT(&obj->names);
1.10 mycroft 458: SIMPLEQ_INIT(&obj->dldags);
459: SIMPLEQ_INIT(&obj->dagmembers);
1.4 christos 460: return obj;
1.1 cgd 461: }
462:
463: /*
464: * Given a set of ELF protection flags, return the corresponding protection
465: * flags for MMAP.
466: */
467: static int
1.30 skrll 468: protflags(int elfflags)
1.1 cgd 469: {
1.4 christos 470: int prot = 0;
1.29 simonb 471:
1.8 kleink 472: if (elfflags & PF_R)
1.4 christos 473: prot |= PROT_READ;
1.1 cgd 474: #ifdef RTLD_LOADER
1.8 kleink 475: if (elfflags & PF_W)
1.4 christos 476: prot |= PROT_WRITE;
1.1 cgd 477: #endif
1.8 kleink 478: if (elfflags & PF_X)
1.4 christos 479: prot |= PROT_EXEC;
480: return prot;
1.1 cgd 481: }
CVSweb <webmaster@jp.NetBSD.org>