2 * Copyright 1996-1998 John D. Polstra.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * $FreeBSD: src/libexec/rtld-elf/map_object.c,v 1.7.2.2 2002/12/28 19:49:41 dillon Exp $
26 * $DragonFly: src/libexec/rtld-elf/map_object.c,v 1.6 2005/03/22 22:56:36 davidxu Exp $
29 #include <sys/param.h>
41 static Elf_Ehdr
*get_elf_header (int, const char *);
42 static int convert_prot(int); /* Elf flags -> mmap protection */
43 static int convert_flags(int); /* Elf flags -> mmap flags */
46 * Map a shared object into memory. The "fd" argument is a file descriptor,
47 * which must be open on the object and positioned at its beginning.
48 * The "path" argument is a pathname that is used only for error messages.
50 * The return value is a pointer to a newly-allocated Obj_Entry structure
51 * for the shared object. Returns NULL on failure.
54 map_object(int fd
, const char *path
, const struct stat
*sb
)
87 hdr
= get_elf_header(fd
, path
);
92 * Scan the program header entries, and save key information.
94 * We rely on there being exactly two load segments, text and data,
97 phdr
= (Elf_Phdr
*) ((char *)hdr
+ hdr
->e_phoff
);
98 phlimit
= phdr
+ hdr
->e_phnum
;
100 phdyn
= phphdr
= phinterp
= phtls
= NULL
;
101 segs
= alloca(sizeof(segs
[0]) * hdr
->e_phnum
);
102 while (phdr
< phlimit
) {
103 switch (phdr
->p_type
) {
110 segs
[++nsegs
] = phdr
;
111 if (segs
[nsegs
]->p_align
< PAGE_SIZE
) {
112 _rtld_error("%s: PT_LOAD segment %d not page-aligned",
133 _rtld_error("%s: object is not dynamically-linked", path
);
138 _rtld_error("%s: too few PT_LOAD segments", path
);
143 * Map the entire address space of the object, to stake out our
144 * contiguous region, and to establish the base address for relocation.
146 base_offset
= trunc_page(segs
[0]->p_offset
);
147 base_vaddr
= trunc_page(segs
[0]->p_vaddr
);
148 base_vlimit
= round_page(segs
[nsegs
]->p_vaddr
+ segs
[nsegs
]->p_memsz
);
149 mapsize
= base_vlimit
- base_vaddr
;
150 base_addr
= hdr
->e_type
== ET_EXEC
? (caddr_t
) base_vaddr
: NULL
;
152 mapbase
= mmap(base_addr
, mapsize
, convert_prot(segs
[0]->p_flags
),
153 convert_flags(segs
[0]->p_flags
), fd
, base_offset
);
154 if (mapbase
== (caddr_t
) -1) {
155 _rtld_error("%s: mmap of entire address space failed: %s",
156 path
, strerror(errno
));
159 if (base_addr
!= NULL
&& mapbase
!= base_addr
) {
160 _rtld_error("%s: mmap returned wrong address: wanted %p, got %p",
161 path
, base_addr
, mapbase
);
162 munmap(mapbase
, mapsize
);
166 for (i
= 0; i
<= nsegs
; i
++) {
167 /* Overlay the segment onto the proper region. */
168 data_offset
= trunc_page(segs
[i
]->p_offset
);
169 data_vaddr
= trunc_page(segs
[i
]->p_vaddr
);
170 data_vlimit
= round_page(segs
[i
]->p_vaddr
+ segs
[i
]->p_filesz
);
171 data_addr
= mapbase
+ (data_vaddr
- base_vaddr
);
172 data_prot
= convert_prot(segs
[i
]->p_flags
);
173 data_flags
= convert_flags(segs
[i
]->p_flags
) | MAP_FIXED
;
174 /* Do not call mmap on the first segment - this is redundant */
175 if (i
&& mmap(data_addr
, data_vlimit
- data_vaddr
, data_prot
,
176 data_flags
, fd
, data_offset
) == (caddr_t
) -1) {
177 _rtld_error("%s: mmap of data failed: %s", path
, strerror(errno
));
181 /* Clear any BSS in the last page of the segment. */
182 clear_vaddr
= segs
[i
]->p_vaddr
+ segs
[i
]->p_filesz
;
183 clear_addr
= mapbase
+ (clear_vaddr
- base_vaddr
);
184 clear_page
= mapbase
+ (trunc_page(clear_vaddr
) - base_vaddr
);
185 if ((nclear
= data_vlimit
- clear_vaddr
) > 0) {
186 /* Make sure the end of the segment is writable */
187 if ((data_prot
& PROT_WRITE
) == 0) {
188 if (mprotect(clear_page
, PAGE_SIZE
, data_prot
|PROT_WRITE
) < 0) {
189 _rtld_error("%s: mprotect failed: %s", path
,
195 memset(clear_addr
, 0, nclear
);
198 * reset the data protection back, enable the segment to be
199 * coredumped since we modified it.
201 if ((data_prot
& PROT_WRITE
) == 0) {
202 madvise(clear_page
, PAGE_SIZE
, MADV_CORE
);
203 mprotect(clear_page
, PAGE_SIZE
, data_prot
);
207 /* Overlay the BSS segment onto the proper region. */
208 bss_vaddr
= data_vlimit
;
209 bss_vlimit
= round_page(segs
[i
]->p_vaddr
+ segs
[i
]->p_memsz
);
210 bss_addr
= mapbase
+ (bss_vaddr
- base_vaddr
);
211 if (bss_vlimit
> bss_vaddr
) { /* There is something to do */
212 if (mmap(bss_addr
, bss_vlimit
- bss_vaddr
, data_prot
,
213 MAP_PRIVATE
|MAP_FIXED
|MAP_ANON
, -1, 0) == (caddr_t
) -1) {
214 _rtld_error("%s: mmap of bss failed: %s", path
,
223 obj
->dev
= sb
->st_dev
;
224 obj
->ino
= sb
->st_ino
;
226 obj
->mapbase
= mapbase
;
227 obj
->mapsize
= mapsize
;
228 obj
->textsize
= round_page(segs
[0]->p_vaddr
+ segs
[0]->p_memsz
) -
230 obj
->vaddrbase
= base_vaddr
;
231 obj
->relocbase
= mapbase
- base_vaddr
;
232 obj
->dynamic
= (const Elf_Dyn
*) (obj
->relocbase
+ phdyn
->p_vaddr
);
233 if (hdr
->e_entry
!= 0)
234 obj
->entry
= (caddr_t
) (obj
->relocbase
+ hdr
->e_entry
);
235 if (phphdr
!= NULL
) {
236 obj
->phdr
= (const Elf_Phdr
*) (obj
->relocbase
+ phphdr
->p_vaddr
);
237 obj
->phsize
= phphdr
->p_memsz
;
239 if (phinterp
!= NULL
)
240 obj
->interp
= (const char *) (obj
->relocbase
+ phinterp
->p_vaddr
);
242 tls_dtv_generation
++;
243 obj
->tlsindex
= ++tls_max_index
;
244 obj
->tlssize
= phtls
->p_memsz
;
245 obj
->tlsalign
= phtls
->p_align
;
246 obj
->tlsinitsize
= phtls
->p_filesz
;
247 obj
->tlsinit
= mapbase
+ phtls
->p_vaddr
;
253 get_elf_header (int fd
, const char *path
)
261 if ((nbytes
= read(fd
, u
.buf
, PAGE_SIZE
)) == -1) {
262 _rtld_error("%s: read error: %s", path
, strerror(errno
));
266 /* Make sure the file is valid */
267 if (nbytes
< (ssize_t
)sizeof(Elf_Ehdr
) || !IS_ELF(u
.hdr
)) {
268 _rtld_error("%s: invalid file format", path
);
271 if (u
.hdr
.e_ident
[EI_CLASS
] != ELF_TARG_CLASS
272 || u
.hdr
.e_ident
[EI_DATA
] != ELF_TARG_DATA
) {
273 _rtld_error("%s: unsupported file layout", path
);
276 if (u
.hdr
.e_ident
[EI_VERSION
] != EV_CURRENT
277 || u
.hdr
.e_version
!= EV_CURRENT
) {
278 _rtld_error("%s: unsupported file version", path
);
281 if (u
.hdr
.e_type
!= ET_EXEC
&& u
.hdr
.e_type
!= ET_DYN
) {
282 _rtld_error("%s: unsupported file type", path
);
285 if (u
.hdr
.e_machine
!= ELF_TARG_MACH
) {
286 _rtld_error("%s: unsupported machine", path
);
291 * We rely on the program header being in the first page. This is
292 * not strictly required by the ABI specification, but it seems to
293 * always true in practice. And, it simplifies things considerably.
295 if (u
.hdr
.e_phentsize
!= sizeof(Elf_Phdr
)) {
297 "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path
);
300 if (u
.hdr
.e_phoff
+ u
.hdr
.e_phnum
* sizeof(Elf_Phdr
) > (size_t)nbytes
) {
301 _rtld_error("%s: program header too large", path
);
309 obj_free(Obj_Entry
*obj
)
314 free_tls_offset(obj
);
316 free(obj
->origin_path
);
318 while (obj
->needed
!= NULL
) {
319 Needed_Entry
*needed
= obj
->needed
;
320 obj
->needed
= needed
->next
;
323 while (!STAILQ_EMPTY(&obj
->dldags
)) {
324 elm
= STAILQ_FIRST(&obj
->dldags
);
325 STAILQ_REMOVE_HEAD(&obj
->dldags
, link
);
328 while (!STAILQ_EMPTY(&obj
->dagmembers
)) {
329 elm
= STAILQ_FIRST(&obj
->dagmembers
);
330 STAILQ_REMOVE_HEAD(&obj
->dagmembers
, link
);
341 obj
= CNEW(Obj_Entry
);
342 STAILQ_INIT(&obj
->dldags
);
343 STAILQ_INIT(&obj
->dagmembers
);
348 * Given a set of ELF protection flags, return the corresponding protection
352 convert_prot(int elfflags
)
365 convert_flags(int elfflags
)
367 int flags
= MAP_PRIVATE
; /* All mappings are private */
370 * Readonly mappings are marked "MAP_NOCORE", because they can be
371 * reconstructed by a debugger.
373 if (!(elfflags
& PF_W
))