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