1 /* $NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll 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.41 2010/10/16 10:27:07 skrll Exp $");
47 #include <sys/types.h>
54 #define munmap minix_munmap
57 #define MINIXVERBOSE 0
59 static int protflags(int); /* Elf flags -> mmap protection */
61 #define EA_UNDEF (~(Elf_Addr)0)
63 static void Pread(void *addr
, size_t size
, int fd
, off_t off
)
66 if((s
=pread(fd
,addr
, size
, off
)) < 0) {
67 _rtld_error("pread failed");
72 fprintf(stderr
, "read 0x%lx bytes from offset 0x%lx to addr 0x%lx\n", size
, off
, addr
);
77 * Map a shared object into memory. The argument is a file descriptor,
78 * which must be open on the object and positioned at its beginning.
80 * The return value is a pointer to a newly-allocated Obj_Entry structure
81 * for the shared object. Returns NULL on failure.
84 _rtld_map_object(const char *path
, int fd
, const struct stat
*sb
)
93 caddr_t mapbase
= MAP_FAILED
;
99 Elf_Addr base_alignment
;
102 Elf_Addr base_vlimit
;
103 Elf_Addr text_vlimit
;
108 Elf_Addr data_vlimit
;
117 Elf_Addr clear_vaddr
;
122 if (sb
!= NULL
&& sb
->st_size
< (off_t
)sizeof (Elf_Ehdr
)) {
123 _rtld_error("%s: unrecognized file format1", path
);
127 obj
= _rtld_obj_new();
128 obj
->path
= xstrdup(path
);
129 obj
->pathlen
= strlen(path
);
131 obj
->dev
= sb
->st_dev
;
132 obj
->ino
= sb
->st_ino
;
136 ehdr
= minix_mmap(NULL
, _rtld_pagesz
, PROT_READ
|PROT_WRITE
,
137 MAP_PREALLOC
|MAP_ANON
, -1, (off_t
)0);
138 Pread(ehdr
, _rtld_pagesz
, fd
, 0);
140 fprintf(stderr
, "minix mmap for header: 0x%lx\n", ehdr
);
143 ehdr
= mmap(NULL
, _rtld_pagesz
, PROT_READ
, MAP_FILE
| MAP_SHARED
, fd
,
147 if (ehdr
== MAP_FAILED
) {
148 _rtld_error("%s: read error: %s", path
, xstrerror(errno
));
151 /* Make sure the file is valid */
152 if (memcmp(ELFMAG
, ehdr
->e_ident
, SELFMAG
) != 0 ||
153 ehdr
->e_ident
[EI_CLASS
] != ELFCLASS
) {
154 _rtld_error("%s: unrecognized file format2 [%x != %x]", path
,
155 ehdr
->e_ident
[EI_CLASS
], ELFCLASS
);
158 /* Elf_e_ident includes class */
159 if (ehdr
->e_ident
[EI_VERSION
] != EV_CURRENT
||
160 ehdr
->e_version
!= EV_CURRENT
||
161 ehdr
->e_ident
[EI_DATA
] != ELFDEFNNAME(MACHDEP_ENDIANNESS
)) {
162 _rtld_error("%s: unsupported file version", path
);
165 if (ehdr
->e_type
!= ET_EXEC
&& ehdr
->e_type
!= ET_DYN
) {
166 _rtld_error("%s: unsupported file type", path
);
169 switch (ehdr
->e_machine
) {
170 ELFDEFNNAME(MACHDEP_ID_CASES
)
172 _rtld_error("%s: unsupported machine", path
);
177 * We rely on the program header being in the first page. This is
178 * not strictly required by the ABI specification, but it seems to
179 * always true in practice. And, it simplifies things considerably.
181 assert(ehdr
->e_phentsize
== sizeof(Elf_Phdr
));
182 assert(ehdr
->e_phoff
+ ehdr
->e_phnum
* sizeof(Elf_Phdr
) <=
186 * Scan the program header entries, and save key information.
188 * We rely on there being exactly two load segments, text and data,
191 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
192 phsize
= ehdr
->e_phnum
* sizeof(phdr
[0]);
194 phdr_vaddr
= EA_UNDEF
;
196 phlimit
= phdr
+ ehdr
->e_phnum
;
198 while (phdr
< phlimit
) {
199 switch (phdr
->p_type
) {
201 obj
->interp
= (void *)(uintptr_t)phdr
->p_vaddr
;
202 dbg(("%s: PT_INTERP %p", obj
->path
, obj
->interp
));
209 dbg(("%s: PT_LOAD %p", obj
->path
, phdr
));
213 phdr_vaddr
= phdr
->p_vaddr
;
214 phdr_memsz
= phdr
->p_memsz
;
215 dbg(("%s: PT_PHDR %p phsize %zu", obj
->path
,
216 (void *)(uintptr_t)phdr_vaddr
, phdr_memsz
));
220 obj
->dynamic
= (void *)(uintptr_t)phdr
->p_vaddr
;
221 dbg(("%s: PT_DYNAMIC %p", obj
->path
, obj
->dynamic
));
227 phdr
= (Elf_Phdr
*) ((caddr_t
)ehdr
+ ehdr
->e_phoff
);
228 obj
->entry
= (void *)(uintptr_t)ehdr
->e_entry
;
230 _rtld_error("%s: not dynamically linked", path
);
234 _rtld_error("%s: wrong number of segments (%d != 2)", path
,
240 * Map the entire address space of the object as a file
241 * region to stake out our contiguous region and establish a
242 * base for relocation. We use a file mapping so that
243 * the kernel will give us whatever alignment is appropriate
244 * for the platform we're running on.
246 * We map it using the text protection, map the data segment
247 * into the right place, then map an anon segment for the bss
248 * and unmap the gaps left by padding to alignment.
252 base_alignment
= segs
[0]->p_align
;
254 base_offset
= round_down(segs
[0]->p_offset
);
255 base_vaddr
= round_down(segs
[0]->p_vaddr
);
256 base_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_memsz
);
257 text_vlimit
= round_up(segs
[0]->p_vaddr
+ segs
[0]->p_memsz
);
258 text_flags
= protflags(segs
[0]->p_flags
);
259 data_offset
= round_down(segs
[1]->p_offset
);
260 data_vaddr
= round_down(segs
[1]->p_vaddr
);
261 data_vlimit
= round_up(segs
[1]->p_vaddr
+ segs
[1]->p_filesz
);
262 data_flags
= protflags(segs
[1]->p_flags
);
264 clear_vaddr
= segs
[1]->p_vaddr
+ segs
[1]->p_filesz
;
267 obj
->textsize
= text_vlimit
- base_vaddr
;
268 obj
->vaddrbase
= base_vaddr
;
269 obj
->isdynamic
= ehdr
->e_type
== ET_DYN
;
271 obj
->phdr_loaded
= false;
272 for (i
= 0; i
< nsegs
; i
++) {
273 if (phdr_vaddr
!= EA_UNDEF
&&
274 segs
[i
]->p_vaddr
<= phdr_vaddr
&&
275 segs
[i
]->p_memsz
>= phdr_memsz
) {
276 obj
->phdr_loaded
= true;
279 if (segs
[i
]->p_offset
<= ehdr
->e_phoff
&&
280 segs
[i
]->p_memsz
>= phsize
) {
281 phdr_vaddr
= segs
[i
]->p_vaddr
+ ehdr
->e_phoff
;
283 obj
->phdr_loaded
= true;
287 if (obj
->phdr_loaded
) {
288 obj
->phdr
= (void *)(uintptr_t)phdr_vaddr
;
289 obj
->phsize
= phdr_memsz
;
292 buf
= xmalloc(phsize
);
294 _rtld_error("%s: cannot allocate program header", path
);
297 memcpy(buf
, phdr
, phsize
);
299 obj
->phsize
= phsize
;
301 dbg(("%s: phdr %p phsize %zu (%s)", obj
->path
, obj
->phdr
, obj
->phsize
,
302 obj
->phdr_loaded
? "loaded" : "allocated"));
304 /* Unmap header if it overlaps the first load section. */
305 if (base_offset
< _rtld_pagesz
) {
306 munmap(ehdr
, _rtld_pagesz
);
307 obj
->ehdr
= MAP_FAILED
;
311 * Calculate log2 of the base section alignment.
315 if (base_alignment
> _rtld_pagesz
) {
316 unsigned int log2
= 0;
317 for (; base_alignment
> 1; base_alignment
>>= 1)
319 mapflags
= MAP_ALIGNED(log2
);
324 base_addr
= obj
->isdynamic
? NULL
: (caddr_t
)base_vaddr
;
328 mapsize
= base_vlimit
- base_vaddr
;
331 mapbase
= mmap(base_addr
, mapsize
, text_flags
,
332 mapflags
| MAP_FILE
| MAP_PRIVATE
, fd
, base_offset
);
334 mapbase
= minix_mmap(base_addr
, mapsize
, PROT_READ
|PROT_WRITE
,
335 MAP_ANON
| MAP_PREALLOC
, -1, 0);
337 fprintf(stderr
, "minix mmap for whole block: 0x%lx-0x%lx\n", mapbase
, mapbase
+mapsize
);
339 Pread(mapbase
, obj
->textsize
, fd
, 0);
341 if (mapbase
== MAP_FAILED
) {
342 _rtld_error("mmap of entire address space failed: %s",
347 /* Overlay the data segment onto the proper region. */
348 data_addr
= mapbase
+ (data_vaddr
- base_vaddr
);
350 Pread(data_addr
, data_vlimit
- data_vaddr
, fd
, data_offset
);
352 if (mmap(data_addr
, data_vlimit
- data_vaddr
, data_flags
,
353 MAP_FILE
| MAP_PRIVATE
| MAP_FIXED
, fd
, data_offset
) ==
355 _rtld_error("mmap of data failed: %s", xstrerror(errno
));
361 bsssize
= base_vlimit
- data_vlimit
;
363 /* Overlay the bss segment onto the proper region. */
364 if (mmap(mapbase
+ data_vlimit
- base_vaddr
, bsssize
,
365 data_flags
, MAP_ANON
| MAP_PRIVATE
| MAP_FIXED
, -1, 0) ==
367 _rtld_error("mmap of bss (at 0x%lx, 0x%lx bytes) failed: %s",
368 mapbase
+ data_vlimit
- base_vaddr
, bsssize
, xstrerror(errno
));
373 /* Unmap the gap between the text and data. */
374 gap_addr
= mapbase
+ round_up(text_vlimit
- base_vaddr
);
375 gap_size
= data_addr
- gap_addr
;
377 if (gap_size
!= 0 && mprotect(gap_addr
, gap_size
, PROT_NONE
) == -1) {
378 _rtld_error("mprotect of text -> data gap failed: %s",
385 /* Clear any BSS in the last page of the data segment. */
386 clear_addr
= mapbase
+ (clear_vaddr
- base_vaddr
);
387 if ((nclear
= data_vlimit
- clear_vaddr
) > 0)
388 memset(clear_addr
, 0, nclear
);
390 /* Non-file portion of BSS mapped above. */
393 obj
->mapbase
= mapbase
;
394 obj
->mapsize
= mapsize
;
395 obj
->relocbase
= mapbase
- base_vaddr
;
398 obj
->dynamic
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->dynamic
);
400 obj
->entry
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->entry
);
402 obj
->interp
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->interp
);
403 if (obj
->phdr_loaded
)
404 obj
->phdr
= (void *)(obj
->relocbase
+ (Elf_Addr
)(uintptr_t)obj
->phdr
);
409 if (obj
->ehdr
!= MAP_FAILED
)
410 munmap(obj
->ehdr
, _rtld_pagesz
);
411 if (mapbase
!= MAP_FAILED
)
412 munmap(mapbase
, mapsize
);
418 _rtld_obj_free(Obj_Entry
*obj
)
423 while (obj
->needed
!= NULL
) {
424 Needed_Entry
*needed
= obj
->needed
;
425 obj
->needed
= needed
->next
;
428 while ((elm
= SIMPLEQ_FIRST(&obj
->dldags
)) != NULL
) {
429 SIMPLEQ_REMOVE_HEAD(&obj
->dldags
, link
);
432 while ((elm
= SIMPLEQ_FIRST(&obj
->dagmembers
)) != NULL
) {
433 SIMPLEQ_REMOVE_HEAD(&obj
->dagmembers
, link
);
436 if (!obj
->phdr_loaded
)
437 xfree((void *)(uintptr_t)obj
->phdr
);
440 _rtld_combreloc_reset(obj
);
449 obj
= CNEW(Obj_Entry
);
450 SIMPLEQ_INIT(&obj
->dldags
);
451 SIMPLEQ_INIT(&obj
->dagmembers
);
456 * Given a set of ELF protection flags, return the corresponding protection
460 protflags(int elfflags
)