1 /* $NetBSD: map_object.c,v 1.45 2012/10/13 21:13:07 dholland 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.45 2012/10/13 21:13:07 dholland Exp $");
46 #include <sys/types.h>
53 #define munmap minix_munmap
56 #define MINIXVERBOSE 0
62 static int protflags(int); /* Elf flags -> mmap protection */
64 #define EA_UNDEF (~(Elf_Addr)0)
66 static void Pread(void *addr
, size_t size
, int fd
, off_t off
)
69 if((s
=pread(fd
,addr
, size
, off
)) < 0) {
70 _rtld_error("pread failed");
75 fprintf(stderr
, "read 0x%lx bytes from offset 0x%lx to addr 0x%lx\n", size
, off
, addr
);
80 * Map a shared object into memory. The argument is a file descriptor,
81 * which must be open on the object and positioned at its beginning.
83 * The return value is a pointer to a newly-allocated Obj_Entry structure
84 * for the shared object. Returns NULL on failure.
87 _rtld_map_object(const char *path
, int fd
, const struct stat
*sb
)
92 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
99 caddr_t mapbase
= MAP_FAILED
;
104 Elf_Addr base_alignment
;
107 Elf_Addr base_vlimit
;
108 Elf_Addr text_vlimit
;
113 Elf_Addr data_vlimit
;
116 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
117 Elf_Addr tls_vaddr
= 0; /* Noise GCC */
121 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
127 Elf_Addr clear_vaddr
;
132 if (sb
!= NULL
&& sb
->st_size
< (off_t
)sizeof (Elf_Ehdr
)) {
133 _rtld_error("%s: not ELF file (too short)", path
);
137 obj
= _rtld_obj_new();
138 obj
->path
= xstrdup(path
);
139 obj
->pathlen
= strlen(path
);
141 obj
->dev
= sb
->st_dev
;
142 obj
->ino
= sb
->st_ino
;
146 ehdr
= minix_mmap(NULL
, _rtld_pagesz
, PROT_READ
|PROT_WRITE
,
147 MAP_PREALLOC
|MAP_ANON
, -1, (off_t
)0);
148 Pread(ehdr
, _rtld_pagesz
, fd
, 0);
150 fprintf(stderr
, "minix mmap for header: 0x%lx\n", ehdr
);
153 ehdr
= mmap(NULL
, _rtld_pagesz
, PROT_READ
, MAP_FILE
| MAP_SHARED
, fd
,
157 if (ehdr
== MAP_FAILED
) {
158 _rtld_error("%s: read error: %s", path
, xstrerror(errno
));
161 /* Make sure the file is valid */
162 if (memcmp(ELFMAG
, ehdr
->e_ident
, SELFMAG
) != 0) {
163 _rtld_error("%s: not ELF file (magic number bad)", path
);
166 if (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
) {
167 _rtld_error("%s: invalid ELF class %x; expected %x", path
,
168 ehdr
->e_ident
[EI_CLASS
], ELFCLASS
);
171 /* Elf_e_ident includes class */
172 if (ehdr
->e_ident
[EI_VERSION
] != EV_CURRENT
||
173 ehdr
->e_version
!= EV_CURRENT
||
174 ehdr
->e_ident
[EI_DATA
] != ELFDEFNNAME(MACHDEP_ENDIANNESS
)) {
175 _rtld_error("%s: unsupported file version", path
);
178 if (ehdr
->e_type
!= ET_EXEC
&& ehdr
->e_type
!= ET_DYN
) {
179 _rtld_error("%s: unsupported file type", path
);
182 switch (ehdr
->e_machine
) {
183 ELFDEFNNAME(MACHDEP_ID_CASES
)
185 _rtld_error("%s: unsupported machine", path
);
190 * We rely on the program header being in the first page. This is
191 * not strictly required by the ABI specification, but it seems to
192 * always true in practice. And, it simplifies things considerably.
194 assert(ehdr
->e_phentsize
== sizeof(Elf_Phdr
));
195 assert(ehdr
->e_phoff
+ ehdr
->e_phnum
* sizeof(Elf_Phdr
) <=
199 * Scan the program header entries, and save key information.
201 * We rely on there being exactly two load segments, text and data,
204 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
205 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
208 phsize
= ehdr
->e_phnum
* sizeof(phdr
[0]);
210 phdr_vaddr
= EA_UNDEF
;
212 phlimit
= phdr
+ ehdr
->e_phnum
;
214 while (phdr
< phlimit
) {
215 switch (phdr
->p_type
) {
217 obj
->interp
= (void *)(uintptr_t)phdr
->p_vaddr
;
218 dbg(("%s: PT_INTERP %p", obj
->path
, obj
->interp
));
227 #define PRImemsz PRIu64
229 #define PRImemsz PRIu32
231 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_LOAD",
232 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
236 phdr_vaddr
= phdr
->p_vaddr
;
237 phdr_memsz
= phdr
->p_memsz
;
238 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_PHDR",
239 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
243 obj
->dynamic
= (void *)(uintptr_t)phdr
->p_vaddr
;
244 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_DYNAMIC",
245 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
248 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
251 dbg(("%s: %s %p phsize %" PRImemsz
, obj
->path
, "PT_TLS",
252 (void *)(uintptr_t)phdr
->p_vaddr
, phdr
->p_memsz
));
259 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
260 obj
->entry
= (void *)(uintptr_t)ehdr
->e_entry
;
262 _rtld_error("%s: not dynamically linked", path
);
266 _rtld_error("%s: wrong number of segments (%d != 2)", path
,
272 * Map the entire address space of the object as a file
273 * region to stake out our contiguous region and establish a
274 * base for relocation. We use a file mapping so that
275 * the kernel will give us whatever alignment is appropriate
276 * for the platform we're running on.
278 * We map it using the text protection, map the data segment
279 * into the right place, then map an anon segment for the bss
280 * and unmap the gaps left by padding to alignment.
284 base_alignment
= segs
[0]->p_align
;
286 base_offset
= round_down(segs
[0]->p_offset
);
287 base_vaddr
= round_down(segs
[0]->p_vaddr
);
288 base_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_memsz
);
289 text_vlimit
= round_up(segs
[0]->p_vaddr
+ segs
[0]->p_memsz
);
290 text_flags
= protflags(segs
[0]->p_flags
);
291 data_offset
= round_down(segs
[1]->p_offset
);
292 data_vaddr
= round_down(segs
[1]->p_vaddr
);
293 data_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_filesz
);
294 data_flags
= protflags(segs
[1]->p_flags
);
296 clear_vaddr
= segs
[1]->p_vaddr
+ segs
[1]->p_filesz
;
299 obj
->textsize
= text_vlimit
- base_vaddr
;
300 obj
->vaddrbase
= base_vaddr
;
301 obj
->isdynamic
= ehdr
->e_type
== ET_DYN
;
303 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
305 ++_rtld_tls_dtv_generation
;
306 obj
->tlsindex
= ++_rtld_tls_max_index
;
307 obj
->tlssize
= phtls
->p_memsz
;
308 obj
->tlsalign
= phtls
->p_align
;
309 obj
->tlsinitsize
= phtls
->p_filesz
;
310 tls_vaddr
= phtls
->p_vaddr
;
314 obj
->phdr_loaded
= false;
315 for (i
= 0; i
< nsegs
; i
++) {
316 if (phdr_vaddr
!= EA_UNDEF
&&
317 segs
[i
]->p_vaddr
<= phdr_vaddr
&&
318 segs
[i
]->p_memsz
>= phdr_memsz
) {
319 obj
->phdr_loaded
= true;
322 if (segs
[i
]->p_offset
<= ehdr
->e_phoff
&&
323 segs
[i
]->p_memsz
>= phsize
) {
324 phdr_vaddr
= segs
[i
]->p_vaddr
+ ehdr
->e_phoff
;
326 obj
->phdr_loaded
= true;
330 if (obj
->phdr_loaded
) {
331 obj
->phdr
= (void *)(uintptr_t)phdr_vaddr
;
332 obj
->phsize
= phdr_memsz
;
335 buf
= xmalloc(phsize
);
337 _rtld_error("%s: cannot allocate program header", path
);
340 memcpy(buf
, phdr
, phsize
);
342 obj
->phsize
= phsize
;
344 dbg(("%s: phdr %p phsize %zu (%s)", obj
->path
, obj
->phdr
, obj
->phsize
,
345 obj
->phdr_loaded
? "loaded" : "allocated"));
347 /* Unmap header if it overlaps the first load section. */
348 if (base_offset
< _rtld_pagesz
) {
349 munmap(ehdr
, _rtld_pagesz
);
350 obj
->ehdr
= MAP_FAILED
;
354 * Calculate log2 of the base section alignment.
358 if (base_alignment
> _rtld_pagesz
) {
359 unsigned int log2
= 0;
360 for (; base_alignment
> 1; base_alignment
>>= 1)
362 mapflags
= MAP_ALIGNED(log2
);
367 base_addr
= obj
->isdynamic
? NULL
: (caddr_t
)base_vaddr
;
371 mapsize
= base_vlimit
- base_vaddr
;
374 mapbase
= mmap(base_addr
, mapsize
, text_flags
,
375 mapflags
| MAP_FILE
| MAP_PRIVATE
, fd
, base_offset
);
377 mapbase
= minix_mmap(base_addr
, mapsize
, PROT_READ
|PROT_WRITE
,
378 MAP_ANON
| MAP_PREALLOC
, -1, 0);
380 fprintf(stderr
, "minix mmap for whole block: 0x%lx-0x%lx\n", mapbase
, mapbase
+mapsize
);
382 Pread(mapbase
, obj
->textsize
, fd
, 0);
384 if (mapbase
== MAP_FAILED
) {
385 _rtld_error("mmap of entire address space failed: %s",
390 /* Overlay the data segment onto the proper region. */
391 data_addr
= mapbase
+ (data_vaddr
- base_vaddr
);
393 Pread(data_addr
, data_vlimit
- data_vaddr
, fd
, data_offset
);
395 if (mmap(data_addr
, data_vlimit
- data_vaddr
, data_flags
,
396 MAP_FILE
| MAP_PRIVATE
| MAP_FIXED
, fd
, data_offset
) ==
398 _rtld_error("mmap of data failed: %s", xstrerror(errno
));
402 /* Overlay the bss segment onto the proper region. */
403 if (mmap(mapbase
+ data_vlimit
- base_vaddr
, base_vlimit
- data_vlimit
,
404 data_flags
, MAP_ANON
| MAP_PRIVATE
| MAP_FIXED
, -1, 0) ==
406 _rtld_error("mmap of bss failed: %s", xstrerror(errno
));
410 /* Unmap the gap between the text and data. */
411 gap_addr
= mapbase
+ round_up(text_vlimit
- base_vaddr
);
412 gap_size
= data_addr
- gap_addr
;
413 if (gap_size
!= 0 && mprotect(gap_addr
, gap_size
, PROT_NONE
) == -1) {
414 _rtld_error("mprotect of text -> data gap failed: %s",
421 /* Clear any BSS in the last page of the data segment. */
422 clear_addr
= mapbase
+ (clear_vaddr
- base_vaddr
);
423 if ((nclear
= data_vlimit
- clear_vaddr
) > 0)
424 memset(clear_addr
, 0, nclear
);
426 /* Non-file portion of BSS mapped above. */
429 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
431 obj
->tlsinit
= mapbase
+ tls_vaddr
;
434 obj
->mapbase
= mapbase
;
435 obj
->mapsize
= mapsize
;
436 obj
->relocbase
= mapbase
- base_vaddr
;
439 obj
->dynamic
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->dynamic
);
441 obj
->entry
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->entry
);
443 obj
->interp
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->interp
);
444 if (obj
->phdr_loaded
)
445 obj
->phdr
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->phdr
);
450 if (obj
->ehdr
!= MAP_FAILED
)
451 munmap(obj
->ehdr
, _rtld_pagesz
);
452 if (mapbase
!= MAP_FAILED
)
453 munmap(mapbase
, mapsize
);
459 _rtld_obj_free(Obj_Entry
*obj
)
463 #if defined(__HAVE_TLS_VARIANT_I) || defined(__HAVE_TLS_VARIANT_II)
465 _rtld_tls_offset_free(obj
);
468 while (obj
->needed
!= NULL
) {
469 Needed_Entry
*needed
= obj
->needed
;
470 obj
->needed
= needed
->next
;
473 while ((elm
= SIMPLEQ_FIRST(&obj
->dldags
)) != NULL
) {
474 SIMPLEQ_REMOVE_HEAD(&obj
->dldags
, link
);
477 while ((elm
= SIMPLEQ_FIRST(&obj
->dagmembers
)) != NULL
) {
478 SIMPLEQ_REMOVE_HEAD(&obj
->dagmembers
, link
);
481 if (!obj
->phdr_loaded
)
482 xfree((void *)(uintptr_t)obj
->phdr
);
485 _rtld_combreloc_reset(obj
);
494 obj
= CNEW(Obj_Entry
);
495 SIMPLEQ_INIT(&obj
->dldags
);
496 SIMPLEQ_INIT(&obj
->dagmembers
);
501 * Given a set of ELF protection flags, return the corresponding protection
505 protflags(int elfflags
)