112611Sasmotrak/*	$NetBSD: map_object.c,v 1.42 2011/03/09 23:10:07 joerg Exp $	 */
212611Sasmotrak
312611Sasmotrak/*
412611Sasmotrak * Copyright 1996 John D. Polstra.
512611Sasmotrak * Copyright 1996 Matt Thomas <matt@3am-software.com>
612611Sasmotrak * Copyright 2002 Charles M. Hannum <root@ihack.net>
712611Sasmotrak * All rights reserved.
812611Sasmotrak *
912611Sasmotrak * Redistribution and use in source and binary forms, with or without
1012611Sasmotrak * modification, are permitted provided that the following conditions
1112611Sasmotrak * are met:
1212611Sasmotrak * 1. Redistributions of source code must retain the above copyright
1312611Sasmotrak *    notice, this list of conditions and the following disclaimer.
1412611Sasmotrak * 2. Redistributions in binary form must reproduce the above copyright
1512611Sasmotrak *    notice, this list of conditions and the following disclaimer in the
1612611Sasmotrak *    documentation and/or other materials provided with the distribution.
1712611Sasmotrak * 3. All advertising materials mentioning features or use of this software
1812611Sasmotrak *    must display the following acknowledgement:
1912611Sasmotrak *      This product includes software developed by John Polstra.
2012611Sasmotrak * 4. The name of the author may not be used to endorse or promote products
2112611Sasmotrak *    derived from this software without specific prior written permission.
2212611Sasmotrak *
2312611Sasmotrak * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2412611Sasmotrak * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2512611Sasmotrak * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2612611Sasmotrak * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2712611Sasmotrak * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2812611Sasmotrak * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2912611Sasmotrak * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3012611Sasmotrak * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3112611Sasmotrak * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3212611Sasmotrak * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3312611Sasmotrak */
3412611Sasmotrak
3512611Sasmotrak#include <sys/cdefs.h>
3612611Sasmotrak#ifndef lint
3712611Sasmotrak__RCSID("$NetBSD: map_object.c,v 1.42 2011/03/09 23:10:07 joerg Exp $");
3812611Sasmotrak#endif /* not lint */
3912611Sasmotrak
4012611Sasmotrak#include <errno.h>
4112611Sasmotrak#include <stddef.h>
4212611Sasmotrak#include <stdlib.h>
4312611Sasmotrak#include <string.h>
4412611Sasmotrak#include <unistd.h>
4512611Sasmotrak#include <sys/stat.h>
4612611Sasmotrak#include <sys/types.h>
4712611Sasmotrak#include <sys/mman.h>
4812611Sasmotrak
4912611Sasmotrak#include "debug.h"
5012611Sasmotrak#include "rtld.h"
5112611Sasmotrak
5212611Sasmotrakstatic int protflags(int);	/* Elf flags -> mmap protection */
5312611Sasmotrak
5412611Sasmotrak#define EA_UNDEF		(~(Elf_Addr)0)
5512611Sasmotrak
5612611Sasmotrak/*
5712611Sasmotrak * Map a shared object into memory.  The argument is a file descriptor,
5812611Sasmotrak * which must be open on the object and positioned at its beginning.
5912611Sasmotrak *
6012611Sasmotrak * The return value is a pointer to a newly-allocated Obj_Entry structure
6112611Sasmotrak * for the shared object.  Returns NULL on failure.
6212611Sasmotrak */
6312611SasmotrakObj_Entry *
6412611Sasmotrak_rtld_map_object(const char *path, int fd, const struct stat *sb)
6512611Sasmotrak{
6612611Sasmotrak	Obj_Entry	*obj;
6712611Sasmotrak	Elf_Ehdr	*ehdr;
6812611Sasmotrak	Elf_Phdr	*phdr;
6912611Sasmotrak#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
7012611Sasmotrak	Elf_Phdr	*phtls;
7112611Sasmotrak#endif
7212611Sasmotrak	size_t		 phsize;
7312611Sasmotrak	Elf_Phdr	*phlimit;
7412611Sasmotrak	Elf_Phdr	*segs[2];
7512611Sasmotrak	int		 nsegs;
7612611Sasmotrak	caddr_t		 mapbase = MAP_FAILED;
7712611Sasmotrak	size_t		 mapsize = 0;
7812611Sasmotrak	int		 mapflags;
7912611Sasmotrak	Elf_Off		 base_offset;
8012611Sasmotrak#ifdef MAP_ALIGNED
8112611Sasmotrak	Elf_Addr	 base_alignment;
8212611Sasmotrak#endif
8312611Sasmotrak	Elf_Addr	 base_vaddr;
8412611Sasmotrak	Elf_Addr	 base_vlimit;
8512611Sasmotrak	Elf_Addr	 text_vlimit;
8612611Sasmotrak	int		 text_flags;
8712611Sasmotrak	caddr_t		 base_addr;
8812611Sasmotrak	Elf_Off		 data_offset;
8912611Sasmotrak	Elf_Addr	 data_vaddr;
9012611Sasmotrak	Elf_Addr	 data_vlimit;
9112611Sasmotrak	int		 data_flags;
9212611Sasmotrak	caddr_t		 data_addr;
9312611Sasmotrak#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
9412611Sasmotrak	Elf_Addr	 tls_vaddr = 0; /* Noise GCC */
9512611Sasmotrak#endif
9612611Sasmotrak	Elf_Addr	 phdr_vaddr;
9712611Sasmotrak	size_t		 phdr_memsz;
9812611Sasmotrak	caddr_t		 gap_addr;
9912611Sasmotrak	size_t		 gap_size;
10012611Sasmotrak	int i;
10112611Sasmotrak#ifdef RTLD_LOADER
10212611Sasmotrak	Elf_Addr	 clear_vaddr;
10312611Sasmotrak	caddr_t		 clear_addr;
10412611Sasmotrak	size_t		 nclear;
10512611Sasmotrak#endif
10612611Sasmotrak
10712611Sasmotrak	if (sb != NULL && sb->st_size < (off_t)sizeof (Elf_Ehdr)) {
10812611Sasmotrak		_rtld_error("%s: unrecognized file format1", path);
10912611Sasmotrak		return NULL;
11012611Sasmotrak	}
11112611Sasmotrak
11212611Sasmotrak	obj = _rtld_obj_new();
11312611Sasmotrak	obj->path = xstrdup(path);
11412611Sasmotrak	obj->pathlen = strlen(path);
11512611Sasmotrak	if (sb != NULL) {
11612611Sasmotrak		obj->dev = sb->st_dev;
11712611Sasmotrak		obj->ino = sb->st_ino;
11812611Sasmotrak	}
11912611Sasmotrak
12012611Sasmotrak	ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
12112611Sasmotrak	    (off_t)0);
12212611Sasmotrak	obj->ehdr = ehdr;
12312611Sasmotrak	if (ehdr == MAP_FAILED) {
12412611Sasmotrak		_rtld_error("%s: read error: %s", path, xstrerror(errno));
12512611Sasmotrak		goto bad;
12612611Sasmotrak	}
12712611Sasmotrak	/* Make sure the file is valid */
12812611Sasmotrak	if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 ||
12912611Sasmotrak	    ehdr->e_ident[EI_CLASS] != ELFCLASS) {
13012611Sasmotrak		_rtld_error("%s: unrecognized file format2 [%x != %x]", path,
13112611Sasmotrak		    ehdr->e_ident[EI_CLASS], ELFCLASS);
13212611Sasmotrak		goto bad;
13312611Sasmotrak	}
13412611Sasmotrak	/* Elf_e_ident includes class */
13512611Sasmotrak	if (ehdr->e_ident[EI_VERSION] != EV_CURRENT ||
13612611Sasmotrak	    ehdr->e_version != EV_CURRENT ||
13712611Sasmotrak	    ehdr->e_ident[EI_DATA] != ELFDEFNNAME(MACHDEP_ENDIANNESS)) {
13812611Sasmotrak		_rtld_error("%s: unsupported file version", path);
13912611Sasmotrak		goto bad;
14012611Sasmotrak	}
14112611Sasmotrak	if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
14212611Sasmotrak		_rtld_error("%s: unsupported file type", path);
14312611Sasmotrak		goto bad;
14412611Sasmotrak	}
14512611Sasmotrak	switch (ehdr->e_machine) {
14612611Sasmotrak		ELFDEFNNAME(MACHDEP_ID_CASES)
14712611Sasmotrak	default:
14812611Sasmotrak		_rtld_error("%s: unsupported machine", path);
14912611Sasmotrak		goto bad;
15012611Sasmotrak	}
15112611Sasmotrak
15212611Sasmotrak	/*
15312611Sasmotrak         * We rely on the program header being in the first page.  This is
15412611Sasmotrak         * not strictly required by the ABI specification, but it seems to
15512611Sasmotrak         * always true in practice.  And, it simplifies things considerably.
15612611Sasmotrak         */
15712611Sasmotrak	assert(ehdr->e_phentsize == sizeof(Elf_Phdr));
15812611Sasmotrak	assert(ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf_Phdr) <=
15912611Sasmotrak	    _rtld_pagesz);
16012611Sasmotrak
16112611Sasmotrak	/*
16212611Sasmotrak         * Scan the program header entries, and save key information.
16312611Sasmotrak         *
16412611Sasmotrak         * We rely on there being exactly two load segments, text and data,
16512611Sasmotrak         * in that order.
16612611Sasmotrak         */
16712611Sasmotrak	phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
16812611Sasmotrak#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
16912611Sasmotrak	phtls = NULL;
17012611Sasmotrak#endif
17112611Sasmotrak	phsize = ehdr->e_phnum * sizeof(phdr[0]);
17212611Sasmotrak	obj->phdr = NULL;
17312611Sasmotrak	phdr_vaddr = EA_UNDEF;
17412611Sasmotrak	phdr_memsz = 0;
17512611Sasmotrak	phlimit = phdr + ehdr->e_phnum;
17612611Sasmotrak	nsegs = 0;
17712611Sasmotrak	while (phdr < phlimit) {
17812611Sasmotrak		switch (phdr->p_type) {
17912611Sasmotrak		case PT_INTERP:
18012611Sasmotrak			obj->interp = (void *)(uintptr_t)phdr->p_vaddr;
18112611Sasmotrak 			dbg(("%s: PT_INTERP %p", obj->path, obj->interp));
18212611Sasmotrak			break;
18312611Sasmotrak
18412611Sasmotrak		case PT_LOAD:
18512611Sasmotrak			if (nsegs < 2)
18612611Sasmotrak				segs[nsegs] = phdr;
18712611Sasmotrak			++nsegs;
18812611Sasmotrak			dbg(("%s: %s %p phsize %zu", obj->path, "PT_LOAD",
18912611Sasmotrak			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
19012611Sasmotrak			break;
19112611Sasmotrak
19212611Sasmotrak		case PT_PHDR:
19312611Sasmotrak			phdr_vaddr = phdr->p_vaddr;
19412611Sasmotrak			phdr_memsz = phdr->p_memsz;
19512611Sasmotrak			dbg(("%s: %s %p phsize %zu", obj->path, "PT_PHDR",
19612611Sasmotrak			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
19712611Sasmotrak			break;
19812611Sasmotrak
19912611Sasmotrak		case PT_DYNAMIC:
20012611Sasmotrak			obj->dynamic = (void *)(uintptr_t)phdr->p_vaddr;
20112611Sasmotrak			dbg(("%s: %s %p phsize %zu", obj->path, "PT_DYNAMIC",
20212611Sasmotrak			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
20312611Sasmotrak			break;
20412611Sasmotrak
20512611Sasmotrak#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
20612611Sasmotrak		case PT_TLS:
20712611Sasmotrak			phtls = phdr;
20812611Sasmotrak			dbg(("%s: %s %p phsize %zu", obj->path, "PT_TLS",
20912611Sasmotrak			    (void *)(uintptr_t)phdr->p_vaddr, phdr->p_memsz));
21012611Sasmotrak			break;
21112611Sasmotrak#endif
21212611Sasmotrak		}
21312611Sasmotrak
21412611Sasmotrak		++phdr;
21512611Sasmotrak	}
21612611Sasmotrak	phdr = (Elf_Phdr *) ((caddr_t)ehdr + ehdr->e_phoff);
21712611Sasmotrak	obj->entry = (void *)(uintptr_t)ehdr->e_entry;
21812611Sasmotrak	if (!obj->dynamic) {
21912611Sasmotrak		_rtld_error("%s: not dynamically linked", path);
22012611Sasmotrak		goto bad;
22112611Sasmotrak	}
22212611Sasmotrak	if (nsegs != 2) {
22312611Sasmotrak		_rtld_error("%s: wrong number of segments (%d != 2)", path,
22412611Sasmotrak		    nsegs);
22512611Sasmotrak		goto bad;
22612611Sasmotrak	}
22712611Sasmotrak
22812611Sasmotrak	/*
22912611Sasmotrak	 * Map the entire address space of the object as a file
23012611Sasmotrak	 * region to stake out our contiguous region and establish a
23112611Sasmotrak	 * base for relocation.  We use a file mapping so that
23212611Sasmotrak	 * the kernel will give us whatever alignment is appropriate
23312611Sasmotrak	 * for the platform we're running on.
23412611Sasmotrak	 *
23512611Sasmotrak	 * We map it using the text protection, map the data segment
23612611Sasmotrak	 * into the right place, then map an anon segment for the bss
23712611Sasmotrak	 * and unmap the gaps left by padding to alignment.
23812611Sasmotrak	 */
23912611Sasmotrak
24012611Sasmotrak#ifdef MAP_ALIGNED
24112611Sasmotrak	base_alignment = segs[0]->p_align;
24212611Sasmotrak#endif
24312611Sasmotrak	base_offset = round_down(segs[0]->p_offset);
24412611Sasmotrak	base_vaddr = round_down(segs[0]->p_vaddr);
24512611Sasmotrak	base_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
24612611Sasmotrak	text_vlimit = round_up(segs[0]->p_vaddr + segs[0]->p_memsz);
24712611Sasmotrak	text_flags = protflags(segs[0]->p_flags);
24812611Sasmotrak	data_offset = round_down(segs[1]->p_offset);
24912611Sasmotrak	data_vaddr = round_down(segs[1]->p_vaddr);
25012611Sasmotrak	data_vlimit = round_up(segs[1]->p_vaddr + segs[1]->p_filesz);
25112611Sasmotrak	data_flags = protflags(segs[1]->p_flags);
25212611Sasmotrak#ifdef RTLD_LOADER
25312611Sasmotrak	clear_vaddr = segs[1]->p_vaddr + segs[1]->p_filesz;
25412611Sasmotrak#endif
25512611Sasmotrak
25612611Sasmotrak	obj->textsize = text_vlimit - base_vaddr;
25712611Sasmotrak	obj->vaddrbase = base_vaddr;
25812611Sasmotrak	obj->isdynamic = ehdr->e_type == ET_DYN;
25912611Sasmotrak
26012611Sasmotrak#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
26112611Sasmotrak	if (phtls != NULL) {
26212611Sasmotrak		++_rtld_tls_dtv_generation;
26312611Sasmotrak		obj->tlsindex = ++_rtld_tls_max_index;
26412611Sasmotrak		obj->tlssize = phtls->p_memsz;
26512611Sasmotrak		obj->tlsalign = phtls->p_align;
26612611Sasmotrak		obj->tlsinitsize = phtls->p_filesz;
26712611Sasmotrak		tls_vaddr = phtls->p_vaddr;
26812611Sasmotrak	}
26912611Sasmotrak#endif
27012611Sasmotrak
27112611Sasmotrak	obj->phdr_loaded = false;
27212611Sasmotrak	for (i = 0; i < nsegs; i++) {
27312611Sasmotrak		if (phdr_vaddr != EA_UNDEF &&
27412611Sasmotrak		    segs[i]->p_vaddr <= phdr_vaddr &&
27512611Sasmotrak		    segs[i]->p_memsz >= phdr_memsz) {
27612611Sasmotrak			obj->phdr_loaded = true;
27712611Sasmotrak			break;
27812611Sasmotrak		}
27912611Sasmotrak		if (segs[i]->p_offset <= ehdr->e_phoff &&
28012611Sasmotrak		    segs[i]->p_memsz >= phsize) {
28112611Sasmotrak			phdr_vaddr = segs[i]->p_vaddr + ehdr->e_phoff;
28212611Sasmotrak			phdr_memsz = phsize;
28312611Sasmotrak			obj->phdr_loaded = true;
28412611Sasmotrak			break;
28512611Sasmotrak		}
28612611Sasmotrak	}
28712611Sasmotrak	if (obj->phdr_loaded) {
28812611Sasmotrak		obj->phdr = (void *)(uintptr_t)phdr_vaddr;
28912611Sasmotrak		obj->phsize = phdr_memsz;
29012611Sasmotrak	} else {
29112611Sasmotrak		Elf_Phdr *buf;
29212611Sasmotrak		buf = xmalloc(phsize);
29312611Sasmotrak		if (buf == NULL) {
29412611Sasmotrak			_rtld_error("%s: cannot allocate program header", path);
29512611Sasmotrak			goto bad;
29612611Sasmotrak		}
29712611Sasmotrak		memcpy(buf, phdr, phsize);
29812611Sasmotrak		obj->phdr = buf;
29912611Sasmotrak		obj->phsize = phsize;
30012611Sasmotrak	}
30112611Sasmotrak	dbg(("%s: phdr %p phsize %zu (%s)", obj->path, obj->phdr, obj->phsize,
30212611Sasmotrak	     obj->phdr_loaded ? "loaded" : "allocated"));
30312611Sasmotrak
30412611Sasmotrak	/* Unmap header if it overlaps the first load section. */
30512611Sasmotrak	if (base_offset < _rtld_pagesz) {
30612611Sasmotrak		munmap(ehdr, _rtld_pagesz);
30712611Sasmotrak		obj->ehdr = MAP_FAILED;
30812611Sasmotrak	}
30912611Sasmotrak
31012611Sasmotrak	/*
31112611Sasmotrak	 * Calculate log2 of the base section alignment.
31212611Sasmotrak	 */
31312611Sasmotrak	mapflags = 0;
31412611Sasmotrak#ifdef MAP_ALIGNED
31512611Sasmotrak	if (base_alignment > _rtld_pagesz) {
31612611Sasmotrak		unsigned int log2 = 0;
31712611Sasmotrak		for (; base_alignment > 1; base_alignment >>= 1)
31812611Sasmotrak			log2++;
31912611Sasmotrak		mapflags = MAP_ALIGNED(log2);
32012611Sasmotrak	}
32112611Sasmotrak#endif
32212611Sasmotrak
32312611Sasmotrak#ifdef RTLD_LOADER
32412611Sasmotrak	base_addr = obj->isdynamic ? NULL : (caddr_t)base_vaddr;
32512611Sasmotrak#else
32612611Sasmotrak	base_addr = NULL;
32712611Sasmotrak#endif
32812611Sasmotrak	mapsize = base_vlimit - base_vaddr;
32912611Sasmotrak	mapbase = mmap(base_addr, mapsize, text_flags,
33012611Sasmotrak	    mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
33112611Sasmotrak	if (mapbase == MAP_FAILED) {
33212611Sasmotrak		_rtld_error("mmap of entire address space failed: %s",
33312611Sasmotrak		    xstrerror(errno));
33412611Sasmotrak		goto bad;
33512611Sasmotrak	}
33612611Sasmotrak
33712611Sasmotrak	/* Overlay the data segment onto the proper region. */
338	data_addr = mapbase + (data_vaddr - base_vaddr);
339	if (mmap(data_addr, data_vlimit - data_vaddr, data_flags,
340	    MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) ==
341	    MAP_FAILED) {
342		_rtld_error("mmap of data failed: %s", xstrerror(errno));
343		goto bad;
344	}
345
346	/* Overlay the bss segment onto the proper region. */
347	if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
348	    data_flags, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) ==
349	    MAP_FAILED) {
350		_rtld_error("mmap of bss failed: %s", xstrerror(errno));
351		goto bad;
352	}
353
354	/* Unmap the gap between the text and data. */
355	gap_addr = mapbase + round_up(text_vlimit - base_vaddr);
356	gap_size = data_addr - gap_addr;
357	if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) {
358		_rtld_error("mprotect of text -> data gap failed: %s",
359		    xstrerror(errno));
360		goto bad;
361	}
362
363#ifdef RTLD_LOADER
364	/* Clear any BSS in the last page of the data segment. */
365	clear_addr = mapbase + (clear_vaddr - base_vaddr);
366	if ((nclear = data_vlimit - clear_vaddr) > 0)
367		memset(clear_addr, 0, nclear);
368
369	/* Non-file portion of BSS mapped above. */
370#endif
371
372#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
373	if (phtls != NULL)
374		obj->tlsinit = mapbase + tls_vaddr;
375#endif
376
377	obj->mapbase = mapbase;
378	obj->mapsize = mapsize;
379	obj->relocbase = mapbase - base_vaddr;
380
381	if (obj->dynamic)
382		obj->dynamic = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->dynamic);
383	if (obj->entry)
384		obj->entry = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->entry);
385	if (obj->interp)
386		obj->interp = (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->interp);
387	if (obj->phdr_loaded)
388		obj->phdr =  (void *)(obj->relocbase + (Elf_Addr)(uintptr_t)obj->phdr);
389
390	return obj;
391
392bad:
393	if (obj->ehdr != MAP_FAILED)
394		munmap(obj->ehdr, _rtld_pagesz);
395	if (mapbase != MAP_FAILED)
396		munmap(mapbase, mapsize);
397	_rtld_obj_free(obj);
398	return NULL;
399}
400
401void
402_rtld_obj_free(Obj_Entry *obj)
403{
404	Objlist_Entry *elm;
405
406#if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
407	if (obj->tls_done)
408		_rtld_tls_offset_free(obj);
409#endif
410	xfree(obj->path);
411	while (obj->needed != NULL) {
412		Needed_Entry *needed = obj->needed;
413		obj->needed = needed->next;
414		xfree(needed);
415	}
416	while ((elm = SIMPLEQ_FIRST(&obj->dldags)) != NULL) {
417		SIMPLEQ_REMOVE_HEAD(&obj->dldags, link);
418		xfree(elm);
419	}
420	while ((elm = SIMPLEQ_FIRST(&obj->dagmembers)) != NULL) {
421		SIMPLEQ_REMOVE_HEAD(&obj->dagmembers, link);
422		xfree(elm);
423	}
424	if (!obj->phdr_loaded)
425		xfree((void *)(uintptr_t)obj->phdr);
426	xfree(obj);
427#ifdef COMBRELOC
428	_rtld_combreloc_reset(obj);
429#endif
430}
431
432Obj_Entry *
433_rtld_obj_new(void)
434{
435	Obj_Entry *obj;
436
437	obj = CNEW(Obj_Entry);
438	SIMPLEQ_INIT(&obj->dldags);
439	SIMPLEQ_INIT(&obj->dagmembers);
440	return obj;
441}
442
443/*
444 * Given a set of ELF protection flags, return the corresponding protection
445 * flags for MMAP.
446 */
447static int
448protflags(int elfflags)
449{
450	int prot = 0;
451
452	if (elfflags & PF_R)
453		prot |= PROT_READ;
454#ifdef RTLD_LOADER
455	if (elfflags & PF_W)
456		prot |= PROT_WRITE;
457#endif
458	if (elfflags & PF_X)
459		prot |= PROT_EXEC;
460	return prot;
461}
462