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 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Redirection ld.so. Based on the 4.x binary compatibility ld.so, used
29 * to redirect aliases for ld.so to the real one.
33 * Import data structures
35 #include <sys/types.h>
37 #include <sys/fcntl.h>
39 #include <sys/sysconfig.h>
44 #include "alias_boot.h"
47 * Local manifest constants and macros.
49 #define ALIGN(x, a) ((int)(x) & ~((int)(a) - 1))
50 #define ROUND(x, a) (((int)(x) + ((int)(a) - 1)) & \
53 #define EMPTY strings[EMPTY_S]
54 #define LDSO strings[LDSO_S]
55 #define ZERO strings[ZERO_S]
56 #define CLOSE (*(funcs[CLOSE_F]))
57 #define FSTATAT (*(funcs[FSTATAT_F]))
58 #define MMAP (*(funcs[MMAP_F]))
59 #define MUNMAP (*(funcs[MUNMAP_F]))
60 #define OPENAT (*(funcs[OPENAT_F]))
61 #define PANIC (*(funcs[PANIC_F]))
62 #define SYSCONFIG (*(funcs[SYSCONFIG_F]))
67 * Alias ld.so entry point -- receives a bootstrap structure and a vector
68 * of strings. The vector is "well-known" to us, and consists of pointers
69 * to string constants. This aliasing bootstrap requires no relocation in
70 * order to run, save for the pointers of constant strings. This second
71 * parameter provides this. Note that this program is carefully coded in
72 * order to maintain the "no bootstrapping" requirement -- it calls only
73 * local functions, uses no intrinsics, etc.
76 __rtld(Elf32_Boot
*ebp
, const char *strings
[], int (*funcs
[])())
78 int i
, j
, p
; /* working */
79 int page_size
= 0; /* size of a page */
80 const char *program_name
= EMPTY
; /* our name */
81 int ldfd
; /* fd assigned to ld.so */
82 int dzfd
= 0; /* fd assigned to /dev/zero */
83 Elf32_Ehdr
*ehdr
; /* ELF header of ld.so */
84 Elf32_Phdr
*phdr
; /* first Phdr in file */
85 Elf32_Phdr
*pptr
; /* working Phdr */
86 Elf32_Phdr
*lph
; /* last loadable Phdr */
87 Elf32_Phdr
*fph
= 0; /* first loadable Phdr */
88 caddr_t maddr
; /* pointer to mapping claim */
89 Elf32_Off mlen
; /* total mapping claim */
90 caddr_t faddr
; /* first program mapping of ld.so */
91 Elf32_Off foff
; /* file offset for segment mapping */
92 Elf32_Off flen
; /* file length for segment mapping */
93 caddr_t addr
; /* working mapping address */
94 caddr_t zaddr
; /* /dev/zero working mapping addr */
95 struct stat sb
; /* stat buffer for sizing */
96 auxv_t
*ap
; /* working aux pointer */
99 * Discover things about our environment: auxiliary vector (if
100 * any), arguments, program name, and the like.
102 while (ebp
->eb_tag
!= 0) {
103 switch (ebp
->eb_tag
) {
105 program_name
= *((char **)ebp
->eb_un
.eb_ptr
);
108 for (ap
= (auxv_t
*)ebp
->eb_un
.eb_ptr
;
109 ap
->a_type
!= AT_NULL
; ap
++)
110 if (ap
->a_type
== AT_PAGESZ
) {
111 page_size
= ap
->a_un
.a_val
;
120 * If we didn't get a page size from looking in the auxiliary
121 * vector, we need to get one now.
123 if (page_size
== 0) {
124 page_size
= SYSCONFIG(_CONFIG_PAGESIZE
);
125 ebp
->eb_tag
= EB_PAGESIZE
, (ebp
++)->eb_un
.eb_val
=
126 (Elf32_Word
)page_size
;
130 * Map in the real ld.so. Note that we're mapping it as
131 * an ELF database, not as a program -- we just want to walk it's
132 * data structures. Further mappings will actually establish the
133 * program in the address space.
135 if ((ldfd
= OPENAT(AT_FDCWD
, LDSO
, O_RDONLY
)) == -1)
137 if (FSTATAT(ldfd
, NULL
, &sb
, 0) == -1)
139 ehdr
= (Elf32_Ehdr
*)MMAP(0, sb
.st_size
, PROT_READ
| PROT_EXEC
,
140 MAP_SHARED
, ldfd
, 0);
141 if (ehdr
== (Elf32_Ehdr
*)-1)
145 * Validate the file we're looking at, ensure it has the correct
146 * ELF structures, such as: ELF magic numbers, coded for 386,
149 if (ehdr
->e_ident
[EI_MAG0
] != ELFMAG0
||
150 ehdr
->e_ident
[EI_MAG1
] != ELFMAG1
||
151 ehdr
->e_ident
[EI_MAG2
] != ELFMAG2
||
152 ehdr
->e_ident
[EI_MAG3
] != ELFMAG3
)
154 if (ehdr
->e_ident
[EI_CLASS
] != ELFCLASS32
||
155 ehdr
->e_ident
[EI_DATA
] != ELFDATA2LSB
)
157 if (ehdr
->e_type
!= ET_DYN
)
159 if (ehdr
->e_machine
!= EM_386
)
161 if (ehdr
->e_version
> EV_CURRENT
)
165 * Point at program headers and start figuring out what to load.
167 phdr
= (Elf32_Phdr
*)((caddr_t
)ehdr
+ ehdr
->e_phoff
);
168 for (p
= 0, pptr
= phdr
; p
< (int)ehdr
->e_phnum
; p
++,
169 pptr
= (Elf32_Phdr
*)((caddr_t
)pptr
+ ehdr
->e_phentsize
))
170 if (pptr
->p_type
== PT_LOAD
) {
173 } else if (pptr
->p_vaddr
<= lph
->p_vaddr
)
179 * We'd better have at least one loadable segment.
185 * Map enough address space to hold the program (as opposed to the
186 * file) represented by ld.so. The amount to be assigned is the
187 * range between the end of the last loadable segment and the
188 * beginning of the first PLUS the alignment of the first segment.
189 * mmap() can assign us any page-aligned address, but the relocations
190 * assume the alignments included in the program header. As an
191 * optimization, however, let's assume that mmap() will actually
192 * give us an aligned address -- since if it does, we can save
193 * an munmap() later on. If it doesn't -- then go try it again.
195 mlen
= ROUND((lph
->p_vaddr
+ lph
->p_memsz
) -
196 ALIGN(fph
->p_vaddr
, page_size
), page_size
);
197 maddr
= (caddr_t
)MMAP(0, mlen
, PROT_READ
| PROT_EXEC
,
198 MAP_SHARED
, ldfd
, 0);
199 if (maddr
== (caddr_t
)-1)
201 faddr
= (caddr_t
)ROUND(maddr
, fph
->p_align
);
204 * Check to see whether alignment skew was really needed.
206 if (faddr
!= maddr
) {
207 (void) MUNMAP(maddr
, mlen
);
208 mlen
= ROUND((lph
->p_vaddr
+ lph
->p_memsz
) -
209 ALIGN(fph
->p_vaddr
, fph
->p_align
) + fph
->p_align
,
211 maddr
= (caddr_t
)MMAP(0, mlen
, PROT_READ
| PROT_EXEC
,
212 MAP_SHARED
, ldfd
, 0);
213 if (maddr
== (caddr_t
)-1)
215 faddr
= (caddr_t
)ROUND(maddr
, fph
->p_align
);
219 * We have the address space reserved, so map each loadable segment.
221 for (p
= 0, pptr
= phdr
; p
< (int)ehdr
->e_phnum
; p
++,
222 pptr
= (Elf32_Phdr
*)((caddr_t
)pptr
+ ehdr
->e_phentsize
)) {
225 * Skip non-loadable segments or segments that don't occupy
228 if ((pptr
->p_type
!= PT_LOAD
) || (pptr
->p_memsz
== 0))
232 * Determine the file offset to which the mapping will
233 * directed (must be aligned) and how much to map (might
234 * be more than the file in the case of .bss.)
236 foff
= ALIGN(pptr
->p_offset
, page_size
);
237 flen
= pptr
->p_memsz
+ (pptr
->p_offset
- foff
);
240 * Set address of this segment relative to our base.
242 addr
= (caddr_t
)ALIGN(faddr
+ pptr
->p_vaddr
, page_size
);
245 * If this is the first program header, record our base
246 * address for later use.
249 ebp
->eb_tag
= EB_LDSO_BASE
;
250 (ebp
++)->eb_un
.eb_ptr
= (Elf32_Addr
)addr
;
254 * Unmap anything from the last mapping address to this
258 (void) MUNMAP(maddr
, addr
- maddr
);
259 mlen
-= addr
- maddr
;
263 * Determine the mapping protection from the section
267 if (pptr
->p_flags
& PF_R
)
269 if (pptr
->p_flags
& PF_W
)
271 if (pptr
->p_flags
& PF_X
)
273 if ((caddr_t
)MMAP((caddr_t
)addr
, flen
, i
,
274 MAP_FIXED
| MAP_PRIVATE
, ldfd
, foff
) == (caddr_t
)-1)
278 * If the memory occupancy of the segment overflows the
279 * definition in the file, we need to "zero out" the
280 * end of the mapping we've established, and if necessary,
281 * map some more space from /dev/zero.
283 if (pptr
->p_memsz
> pptr
->p_filesz
) {
284 foff
= (int)faddr
+ pptr
->p_vaddr
+ pptr
->p_filesz
;
285 zaddr
= (caddr_t
)ROUND(foff
, page_size
);
286 for (j
= 0; j
< (int)(zaddr
- foff
); j
++)
287 *((char *)foff
+ j
) = 0;
288 j
= (faddr
+ pptr
->p_vaddr
+ pptr
->p_memsz
) - zaddr
;
291 dzfd
= OPENAT(AT_FDCWD
, ZERO
, O_RDWR
);
295 if ((caddr_t
)MMAP((caddr_t
)zaddr
, j
, i
,
296 MAP_FIXED
| MAP_PRIVATE
, dzfd
,
303 * Update the mapping claim pointer.
305 maddr
= addr
+ ROUND(flen
, page_size
);
306 mlen
-= maddr
- addr
;
310 * Unmap any final reservation.
313 (void) MUNMAP(maddr
, mlen
);
316 * Clean up file descriptor space we've consumed. Pass along
317 * the /dev/zero file descriptor we got -- every cycle counts.
321 ebp
->eb_tag
= EB_DEVZERO
, (ebp
++)->eb_un
.eb_val
= dzfd
;
323 ebp
->eb_tag
= EB_NULL
, ebp
->eb_un
.eb_val
= 0;
325 /* The two bytes before _rt_boot is for the alias entry point */
326 return (void *) (ehdr
->e_entry
+ faddr
- 2);