4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
35 #include <sys/param.h>
43 * These functions read input files.
44 * On SVR4 and newer systems use mmap(2). On older systems (or on
45 * file systems that don't support mmap, this code simulates mmap.
46 * When reading a file, enough memory is allocated to hold the file's
47 * image, and reads are delayed. When another part of the library
48 * wants to use a part of the file, it "fetches" the needed regions.
50 * An elf descriptor has a bit array to manage this. Each bit
51 * represents one "page" of the file. Pages are grouped into regions.
52 * The page size is tunable. Its value should be at least one disk
53 * block and small enough to avoid superfluous traffic.
55 * NBITS The number of bits in an unsigned. Each unsigned object
56 * holds a "REGION." A byte must have at least 8 bits;
57 * it may have more, though the extra bits at the top of
58 * the unsigned will be unused. Thus, for 9-bit bytes and
59 * 36-bit words, 4 bits at the top will stay empty.
61 * This mechanism gives significant performance gains for library
62 * handling (among other things), because programs typically don't
63 * need to look at entire libraries. The fastest I/O is no I/O.
67 * This global is used to hold the value of the PAGESIZE macro.
69 * This is because the PAGESIZE macro actually calls the
70 * sysconfig(_CONFIG_PAGESIZE) system call and we don't want
71 * to repeatedly call this through out libelf.
73 static unsigned long _elf_pagesize
= 0;
75 #define NBITS (8 * sizeof (unsigned))
76 #define REGSZ (NBITS * _elf_pagesize)
77 #define PGNUM(off) ((off % REGSZ) / _elf_pagesize)
78 #define REGNUM(off) (off / REGSZ)
83 _elf_vm(Elf
* elf
, size_t base
, size_t sz
)
85 register unsigned *hdreg
, hdbit
;
86 unsigned *tlreg
, tlbit
;
93 * always validate region
96 if ((base
+ sz
) > elf
->ed_fsz
) {
98 * range outside of file bounds.
100 _elf_seterr(EFMT_VM
, 0);
105 * If file is mmap()'d and/or the read size is 0
106 * their is nothing else for us to do.
108 if (elf
->ed_vm
== 0 || sz
== 0)
111 * This uses arithmetic instead of masking because
112 * sizeof (unsigned) might not be a power of 2.
114 * Tail gives one beyond the last offset that must be retrieved,
115 * NOT the last in the region.
118 if (elf
->ed_parent
&& elf
->ed_parent
->ed_fd
== -1)
121 base
+= elf
->ed_baseoff
;
122 tail
= base
+ sz
+ _elf_pagesize
- 1;
123 off
= base
- base
% _elf_pagesize
;
124 hdbit
= 1 << PGNUM(base
);
125 tlbit
= 1 << PGNUM(tail
);
126 hdreg
= &elf
->ed_vm
[REGNUM(base
)];
127 tlreg
= &elf
->ed_vm
[REGNUM(tail
)];
131 * Scan through the files 'page table' and make sure
132 * that all of the pages in the specified range have been
133 * loaded into memory. As the pages are loaded the appropriate
134 * bit in the 'page table' is set.
136 * Note: This loop will only read in those pages which havn't
137 * been previously loaded into memory, if the page is
138 * already present it will not be re-loaded.
140 while ((hdreg
!= tlreg
) || (hdbit
!= tlbit
)) {
141 if (*hdreg
& hdbit
) {
144 * Read in a 'chunk' of the elf image.
146 iop
= (Elf_Void
*)(elf
->ed_image
+ off
);
148 * do not read past the end of the file
150 if (elf
->ed_imagesz
- off
< sz
)
151 sz
= elf
->ed_imagesz
- off
;
152 if ((lseek(elf
->ed_fd
, off
,
154 (read(elf
->ed_fd
, iop
, sz
) != sz
)) {
155 _elf_seterr(EIO_VM
, errno
);
161 off
+= _elf_pagesize
;
163 if (elf
->ed_fd
< 0) {
164 _elf_seterr(EREQ_NOFD
, 0);
170 if (hdbit
== ((unsigned)1 << (NBITS
- 1))) {
178 iop
= (Elf_Void
*)(elf
->ed_image
+ off
);
180 * do not read past the end of the file
182 if ((elf
->ed_imagesz
- off
) < sz
)
183 sz
= elf
->ed_imagesz
- off
;
184 if ((lseek(elf
->ed_fd
, off
, SEEK_SET
) != off
) ||
185 (read(elf
->ed_fd
, iop
, sz
) != sz
)) {
186 _elf_seterr(EIO_VM
, errno
);
195 _elf_inmap(Elf
* elf
)
201 register off_t off
= lseek(fd
, (off_t
)0, SEEK_END
);
207 _elf_seterr(EIO_FSZ
, errno
);
211 if ((sz
= (size_t)off
) != off
) {
212 _elf_seterr(EIO_FBIG
, 0);
217 * If the file is mapped, elf->ed_vm will stay null
218 * and elf->ed_image will need to be unmapped someday.
219 * If the file is read, elf->ed_vm and the file image
220 * are allocated together; free() elf->ed_vm.
222 * If the file can be written, disallow mmap.
223 * Otherwise, the input mapping and the output mapping
224 * can collide. Moreover, elf_update will truncate
225 * the file, possibly invalidating the input mapping.
226 * Disallowing input mmap forces the library to malloc
227 * and read the space, which will make output mmap safe.
228 * Using mmap for output reduces the swap space needed
229 * for the process, so that is given preference.
235 if ((elf
->ed_myflags
& EDF_WRITE
) == 0 &&
236 (p
= mmap((char *)0, sz
, PROT_READ
,
237 MAP_PRIVATE
, fd
, (off_t
)0)) != (char *)-1) {
238 elf
->ed_image
= elf
->ed_ident
= p
;
239 elf
->ed_imagesz
= elf
->ed_fsz
= elf
->ed_identsz
= sz
;
244 if (_elf_pagesize
== 0)
245 _elf_pagesize
= PAGESIZE
;
248 * If mmap fails, try read. Some file systems don't mmap
251 register size_t vmsz
= sizeof (unsigned) * (REGNUM(sz
) + 1);
253 if (vmsz
% sizeof (Elf64
) != 0)
254 vmsz
+= sizeof (Elf64
) - vmsz
% sizeof (Elf64
);
255 if ((elf
->ed_vm
= (unsigned *)malloc(vmsz
+ sz
)) == 0) {
256 _elf_seterr(EMEM_VM
, errno
);
259 (void) memset(elf
->ed_vm
, 0, vmsz
);
260 elf
->ed_vmsz
= vmsz
/ sizeof (unsigned);
261 elf
->ed_image
= elf
->ed_ident
= (char *)elf
->ed_vm
+ vmsz
;
262 elf
->ed_imagesz
= elf
->ed_fsz
= elf
->ed_identsz
= sz
;
264 return (_elf_vm(elf
, (size_t)0, (size_t)1));
269 _elf_unmap(char *p
, size_t sz
)
271 if (p
== 0 || sz
== 0)
273 (void) munmap(p
, sz
);