1 /* $NetBSD: map_object.c,v 1.53 2014/10/30 07:53:41 martin Exp $ */
4 * Copyright 1996 John D. Polstra.
5 * Copyright 1996 Matt Thomas <matt@3am-software.com>
6 * Copyright 2002 Charles M. Hannum <root@ihack.net>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
35 #include <sys/cdefs.h>
37 __RCSID("$NetBSD: map_object.c,v 1.53 2014/10/30 07:53:41 martin Exp $");
46 #include <sys/types.h>
52 static int protflags(int); /* Elf flags -> mmap protection */
54 #define EA_UNDEF (~(Elf_Addr)0)
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.
60 * The return value is a pointer to a newly-allocated Obj_Entry structure
61 * for the shared object. Returns NULL on failure.
64 _rtld_map_object(const char *path
, int fd
, const struct stat
*sb
)
69 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
76 caddr_t mapbase
= MAP_FAILED
;
81 Elf_Addr base_alignment
;
93 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
94 Elf_Addr tls_vaddr
= 0; /* Noise GCC */
98 #if defined(__minix) && (defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II))
101 #endif /* defined(__minix) */
104 Elf_Addr clear_vaddr
;
109 if (sb
!= NULL
&& sb
->st_size
< (off_t
)sizeof (Elf_Ehdr
)) {
110 _rtld_error("%s: not ELF file (too short)", path
);
114 obj
= _rtld_obj_new();
115 obj
->path
= xstrdup(path
);
116 obj
->pathlen
= strlen(path
);
118 obj
->dev
= sb
->st_dev
;
119 obj
->ino
= sb
->st_ino
;
122 ehdr
= mmap(NULL
, _rtld_pagesz
, PROT_READ
, MAP_FILE
| MAP_SHARED
, fd
,
125 if (ehdr
== MAP_FAILED
) {
126 _rtld_error("%s: read error: %s", path
, xstrerror(errno
));
129 /* Make sure the file is valid */
130 if (memcmp(ELFMAG
, ehdr
->e_ident
, SELFMAG
) != 0) {
131 _rtld_error("%s: not ELF file (magic number bad)", path
);
134 if (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
) {
135 _rtld_error("%s: invalid ELF class %x; expected %x", path
,
136 ehdr
->e_ident
[EI_CLASS
], ELFCLASS
);
139 /* Elf_e_ident includes class */
140 if (ehdr
->e_ident
[EI_VERSION
] != EV_CURRENT
||
141 ehdr
->e_version
!= EV_CURRENT
||
142 ehdr
->e_ident
[EI_DATA
] != ELFDEFNNAME(MACHDEP_ENDIANNESS
)) {
143 _rtld_error("%s: unsupported file version", path
);
146 if (ehdr
->e_type
!= ET_EXEC
&& ehdr
->e_type
!= ET_DYN
) {
147 _rtld_error("%s: unsupported file type", path
);
150 switch (ehdr
->e_machine
) {
151 ELFDEFNNAME(MACHDEP_ID_CASES
)
153 _rtld_error("%s: unsupported machine", path
);
158 * We rely on the program header being in the first page. This is
159 * not strictly required by the ABI specification, but it seems to
160 * always true in practice. And, it simplifies things considerably.
162 assert(ehdr
->e_phentsize
== sizeof(Elf_Phdr
));
163 assert(ehdr
->e_phoff
+ ehdr
->e_phnum
* sizeof(Elf_Phdr
) <=
167 * Scan the program header entries, and save key information.
169 * We rely on there being exactly two load segments, text and data,
172 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
173 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
176 phsize
= ehdr
->e_phnum
* sizeof(phdr
[0]);
178 phdr_vaddr
= EA_UNDEF
;
180 phlimit
= phdr
+ ehdr
->e_phnum
;
182 while (phdr
< phlimit
) {
183 switch (phdr
->p_type
) {
185 obj
->interp
= (void *)(uintptr_t)phdr
->p_vaddr
;
186 dbg(("%s: PT_INTERP %p", obj
->path
, obj
->interp
));
194 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_LOAD",
195 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
199 phdr_vaddr
= phdr
->p_vaddr
;
200 phdr_memsz
= phdr
->p_memsz
;
201 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_PHDR",
202 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
206 obj
->dynamic
= (void *)(uintptr_t)phdr
->p_vaddr
;
207 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_DYNAMIC",
208 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
211 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
214 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_TLS",
215 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
220 obj
->exidx_start
= (void *)(uintptr_t)phdr
->p_vaddr
;
221 obj
->exidx_sz
= phdr
->p_memsz
;
228 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
229 obj
->entry
= (void *)(uintptr_t)ehdr
->e_entry
;
231 _rtld_error("%s: not dynamically linked", path
);
235 _rtld_error("%s: wrong number of segments (%d != 2)", path
,
241 * Map the entire address space of the object as a file
242 * region to stake out our contiguous region and establish a
243 * base for relocation. We use a file mapping so that
244 * the kernel will give us whatever alignment is appropriate
245 * for the platform we're running on.
247 * We map it using the text protection, map the data segment
248 * into the right place, then map an anon segment for the bss
249 * and unmap the gaps left by padding to alignment.
253 base_alignment
= segs
[0]->p_align
;
255 base_offset
= round_down(segs
[0]->p_offset
);
256 base_vaddr
= round_down(segs
[0]->p_vaddr
);
257 base_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_memsz
);
258 text_vlimit
= round_up(segs
[0]->p_vaddr
+ segs
[0]->p_memsz
);
259 text_flags
= protflags(segs
[0]->p_flags
);
260 data_offset
= round_down(segs
[1]->p_offset
);
261 data_vaddr
= round_down(segs
[1]->p_vaddr
);
262 data_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_filesz
);
263 data_flags
= protflags(segs
[1]->p_flags
);
265 clear_vaddr
= segs
[1]->p_vaddr
+ segs
[1]->p_filesz
;
268 obj
->textsize
= text_vlimit
- base_vaddr
;
269 obj
->vaddrbase
= base_vaddr
;
270 obj
->isdynamic
= ehdr
->e_type
== ET_DYN
;
272 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
274 ++_rtld_tls_dtv_generation
;
275 obj
->tlsindex
= ++_rtld_tls_max_index
;
276 obj
->tlssize
= phtls
->p_memsz
;
277 obj
->tlsalign
= phtls
->p_align
;
278 obj
->tlsinitsize
= phtls
->p_filesz
;
279 tls_vaddr
= phtls
->p_vaddr
;
283 obj
->phdr_loaded
= false;
284 for (i
= 0; i
< nsegs
; i
++) {
285 if (phdr_vaddr
!= EA_UNDEF
&&
286 segs
[i
]->p_vaddr
<= phdr_vaddr
&&
287 segs
[i
]->p_memsz
>= phdr_memsz
) {
288 obj
->phdr_loaded
= true;
291 if (segs
[i
]->p_offset
<= ehdr
->e_phoff
&&
292 segs
[i
]->p_memsz
>= phsize
) {
293 phdr_vaddr
= segs
[i
]->p_vaddr
+ ehdr
->e_phoff
;
295 obj
->phdr_loaded
= true;
299 if (obj
->phdr_loaded
) {
300 obj
->phdr
= (void *)(uintptr_t)phdr_vaddr
;
301 obj
->phsize
= phdr_memsz
;
304 buf
= xmalloc(phsize
);
306 _rtld_error("%s: cannot allocate program header", path
);
309 memcpy(buf
, phdr
, phsize
);
311 obj
->phsize
= phsize
;
313 dbg(("%s: phdr %p phsize %zu (%s)", obj
->path
, obj
->phdr
, obj
->phsize
,
314 obj
->phdr_loaded
? "loaded" : "allocated"));
316 /* Unmap header if it overlaps the first load section. */
317 if (base_offset
< _rtld_pagesz
) {
318 munmap(ehdr
, _rtld_pagesz
);
319 obj
->ehdr
= MAP_FAILED
;
323 * Calculate log2 of the base section alignment.
327 if (base_alignment
> _rtld_pagesz
) {
328 unsigned int log2
= 0;
329 for (; base_alignment
> 1; base_alignment
>>= 1)
331 mapflags
= MAP_ALIGNED(log2
);
336 base_addr
= obj
->isdynamic
? NULL
: (caddr_t
)base_vaddr
;
340 mapsize
= base_vlimit
- base_vaddr
;
341 mapbase
= mmap(base_addr
, mapsize
, text_flags
,
342 mapflags
| MAP_FILE
| MAP_PRIVATE
, fd
, base_offset
);
343 if (mapbase
== MAP_FAILED
) {
344 _rtld_error("mmap of entire address space failed: %s",
349 /* Overlay the data segment onto the proper region. */
350 data_addr
= mapbase
+ (data_vaddr
- base_vaddr
);
351 if (mmap(data_addr
, data_vlimit
- data_vaddr
, data_flags
,
352 MAP_FILE
| MAP_PRIVATE
| MAP_FIXED
, fd
, data_offset
) ==
354 _rtld_error("mmap of data failed: %s", xstrerror(errno
));
358 /* Overlay the bss segment onto the proper region. */
360 /* MINIX's mmap is strict and refuses 0-bytes mappings. */
361 if (0 < base_vlimit
- data_vlimit
)
362 #endif /*defined(__minix) */
363 if (mmap(mapbase
+ data_vlimit
- base_vaddr
, base_vlimit
- data_vlimit
,
364 data_flags
, MAP_ANON
| MAP_PRIVATE
| MAP_FIXED
, -1, 0) ==
366 _rtld_error("mmap of bss failed: %s", xstrerror(errno
));
370 /* Unmap the gap between the text and data. */
371 #if !defined(__minix)
372 gap_addr
= mapbase
+ round_up(text_vlimit
- base_vaddr
);
373 gap_size
= data_addr
- gap_addr
;
374 if (gap_size
!= 0 && mprotect(gap_addr
, gap_size
, PROT_NONE
) == -1) {
375 _rtld_error("mprotect of text -> data gap failed: %s",
379 #endif /* !defined(__minix) */
382 /* Clear any BSS in the last page of the data segment. */
383 clear_addr
= mapbase
+ (clear_vaddr
- base_vaddr
);
384 if ((nclear
= data_vlimit
- clear_vaddr
) > 0)
385 memset(clear_addr
, 0, nclear
);
387 /* Non-file portion of BSS mapped above. */
390 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
392 obj
->tlsinit
= mapbase
+ tls_vaddr
;
395 obj
->mapbase
= mapbase
;
396 obj
->mapsize
= mapsize
;
397 obj
->relocbase
= mapbase
- base_vaddr
;
400 obj
->dynamic
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->dynamic
);
402 obj
->entry
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->entry
);
404 obj
->interp
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->interp
);
405 if (obj
->phdr_loaded
)
406 obj
->phdr
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->phdr
);
408 if (obj
->exidx_start
)
409 obj
->exidx_start
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->exidx_start
);
415 if (obj
->ehdr
!= MAP_FAILED
)
416 munmap(obj
->ehdr
, _rtld_pagesz
);
417 if (mapbase
!= MAP_FAILED
)
418 munmap(mapbase
, mapsize
);
424 _rtld_obj_free(Obj_Entry
*obj
)
429 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
431 _rtld_tls_offset_free(obj
);
434 while (obj
->needed
!= NULL
) {
435 Needed_Entry
*needed
= obj
->needed
;
436 obj
->needed
= needed
->next
;
439 while ((entry
= SIMPLEQ_FIRST(&obj
->names
)) != NULL
) {
440 SIMPLEQ_REMOVE_HEAD(&obj
->names
, link
);
443 while ((elm
= SIMPLEQ_FIRST(&obj
->dldags
)) != NULL
) {
444 SIMPLEQ_REMOVE_HEAD(&obj
->dldags
, link
);
447 while ((elm
= SIMPLEQ_FIRST(&obj
->dagmembers
)) != NULL
) {
448 SIMPLEQ_REMOVE_HEAD(&obj
->dagmembers
, link
);
451 if (!obj
->phdr_loaded
)
452 xfree((void *)(uintptr_t)obj
->phdr
);
454 _rtld_combreloc_reset(obj
);
464 obj
= CNEW(Obj_Entry
);
465 SIMPLEQ_INIT(&obj
->names
);
466 SIMPLEQ_INIT(&obj
->dldags
);
467 SIMPLEQ_INIT(&obj
->dagmembers
);
472 * Given a set of ELF protection flags, return the corresponding protection
476 protflags(int elfflags
)
489 /* Minix has to map it writable so we can do relocations
490 * as we don't have mprotect() yet.
493 #endif /* defined(__minix) */