1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate *
26*7c478bd9Sstevel@tonic-gate * Binary compatibility ld.so. Intercepts the reference of a pre-SVR4
27*7c478bd9Sstevel@tonic-gate * SunOS executable to the dynamic linker, and then redirects to the
28*7c478bd9Sstevel@tonic-gate * "real" post-SVR4 SunOS ld.so.
29*7c478bd9Sstevel@tonic-gate */
30*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
31*7c478bd9Sstevel@tonic-gate
32*7c478bd9Sstevel@tonic-gate /*
33*7c478bd9Sstevel@tonic-gate * Import data structures (N.B.: from 5.x).
34*7c478bd9Sstevel@tonic-gate */
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/sysconfig.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/auxv.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/archsystm.h>
42*7c478bd9Sstevel@tonic-gate #include <elf.h>
43*7c478bd9Sstevel@tonic-gate #include <link.h>
44*7c478bd9Sstevel@tonic-gate
45*7c478bd9Sstevel@tonic-gate /*
46*7c478bd9Sstevel@tonic-gate * Relocation manifest constants and macros.
47*7c478bd9Sstevel@tonic-gate */
48*7c478bd9Sstevel@tonic-gate #define ALIGN(x, a) ((int)(x) & ~((int)(a) - 1))
49*7c478bd9Sstevel@tonic-gate #define ROUND(x, a) (((int)(x) + ((int)(a) - 1)) & \
50*7c478bd9Sstevel@tonic-gate ~((int)(a) - 1))
51*7c478bd9Sstevel@tonic-gate #define DYNAMIC_VERSION2 2
52*7c478bd9Sstevel@tonic-gate #define RELOC_SIZE (sizeof (struct relocation_info))
53*7c478bd9Sstevel@tonic-gate #define RELOCOFF(x) (x)->v2->ld_rel
54*7c478bd9Sstevel@tonic-gate #define MASK(n) ((1<<(n))-1)
55*7c478bd9Sstevel@tonic-gate #define IN_RANGE(v, n) ((-(1<<((n)-1))) <= (v) && (v) < (1<<((n)-1)))
56*7c478bd9Sstevel@tonic-gate
57*7c478bd9Sstevel@tonic-gate void aout_reloc_write();
58*7c478bd9Sstevel@tonic-gate
59*7c478bd9Sstevel@tonic-gate /*
60*7c478bd9Sstevel@tonic-gate * 4.x SunOS Dynamic Link Editor public definitions (much derived from
61*7c478bd9Sstevel@tonic-gate * SunOS 4.x <link.h>.)
62*7c478bd9Sstevel@tonic-gate */
63*7c478bd9Sstevel@tonic-gate
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate * Dynamic linking information. With the exception of
66*7c478bd9Sstevel@tonic-gate * ld_loaded (determined at execution time) and ld_stab_hash (a special
67*7c478bd9Sstevel@tonic-gate * case of relocation handled at execution time), the values in this
68*7c478bd9Sstevel@tonic-gate * structure reflect offsets from the containing link_dynamic structure.
69*7c478bd9Sstevel@tonic-gate */
70*7c478bd9Sstevel@tonic-gate struct link_dynamic_1 {
71*7c478bd9Sstevel@tonic-gate struct link_map *ld_loaded; /* list of loaded objects */
72*7c478bd9Sstevel@tonic-gate long ld_need; /* list of needed objects */
73*7c478bd9Sstevel@tonic-gate long ld_rules; /* search rules for library objects */
74*7c478bd9Sstevel@tonic-gate long ld_got; /* global offset table */
75*7c478bd9Sstevel@tonic-gate long ld_plt; /* procedure linkage table */
76*7c478bd9Sstevel@tonic-gate long ld_rel; /* relocation table */
77*7c478bd9Sstevel@tonic-gate long ld_hash; /* symbol hash table */
78*7c478bd9Sstevel@tonic-gate long ld_stab; /* symbol table itself */
79*7c478bd9Sstevel@tonic-gate long (*ld_stab_hash)(); /* "pointer" to symbol hash function */
80*7c478bd9Sstevel@tonic-gate long ld_buckets; /* number of hash buckets */
81*7c478bd9Sstevel@tonic-gate long ld_symbols; /* symbol strings */
82*7c478bd9Sstevel@tonic-gate long ld_symb_size; /* size of symbol strings */
83*7c478bd9Sstevel@tonic-gate long ld_text; /* size of text area */
84*7c478bd9Sstevel@tonic-gate };
85*7c478bd9Sstevel@tonic-gate
86*7c478bd9Sstevel@tonic-gate struct link_dynamic_2 {
87*7c478bd9Sstevel@tonic-gate struct link_map *ld_loaded; /* list of loaded objects */
88*7c478bd9Sstevel@tonic-gate long ld_need; /* list of needed objects */
89*7c478bd9Sstevel@tonic-gate long ld_rules; /* search rules for library objects */
90*7c478bd9Sstevel@tonic-gate long ld_got; /* global offset table */
91*7c478bd9Sstevel@tonic-gate long ld_plt; /* procedure linkage table */
92*7c478bd9Sstevel@tonic-gate long ld_rel; /* relocation table */
93*7c478bd9Sstevel@tonic-gate long ld_hash; /* symbol hash table */
94*7c478bd9Sstevel@tonic-gate long ld_stab; /* symbol table itself */
95*7c478bd9Sstevel@tonic-gate long (*ld_stab_hash)(); /* "pointer" to symbol hash function */
96*7c478bd9Sstevel@tonic-gate long ld_buckets; /* number of hash buckets */
97*7c478bd9Sstevel@tonic-gate long ld_symbols; /* symbol strings */
98*7c478bd9Sstevel@tonic-gate long ld_symb_size; /* size of symbol strings */
99*7c478bd9Sstevel@tonic-gate long ld_text; /* size of text area */
100*7c478bd9Sstevel@tonic-gate long ld_plt_sz; /* size of procedure linkage table */
101*7c478bd9Sstevel@tonic-gate };
102*7c478bd9Sstevel@tonic-gate
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate * Debugger interface structure.
105*7c478bd9Sstevel@tonic-gate */
106*7c478bd9Sstevel@tonic-gate struct ld_debug {
107*7c478bd9Sstevel@tonic-gate int ldd_version; /* version # of interface */
108*7c478bd9Sstevel@tonic-gate int ldd_in_debugger; /* a debugger is running us */
109*7c478bd9Sstevel@tonic-gate int ldd_sym_loaded; /* we loaded some symbols */
110*7c478bd9Sstevel@tonic-gate char *ldd_bp_addr; /* place for ld-generated bpt */
111*7c478bd9Sstevel@tonic-gate int ldd_bp_inst; /* instruction which was there */
112*7c478bd9Sstevel@tonic-gate struct rtc_symb *ldd_cp; /* commons we built */
113*7c478bd9Sstevel@tonic-gate };
114*7c478bd9Sstevel@tonic-gate
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate * Structure associated with each object which may be or which requires
117*7c478bd9Sstevel@tonic-gate * execution-time link editing. Used by the run-time linkage editor to
118*7c478bd9Sstevel@tonic-gate * identify needed objects and symbol definitions and references.
119*7c478bd9Sstevel@tonic-gate */
120*7c478bd9Sstevel@tonic-gate struct link_dynamic {
121*7c478bd9Sstevel@tonic-gate int ld_version;
122*7c478bd9Sstevel@tonic-gate struct ld_debug *ldd;
123*7c478bd9Sstevel@tonic-gate union {
124*7c478bd9Sstevel@tonic-gate struct link_dynamic_1 *ld_1;
125*7c478bd9Sstevel@tonic-gate struct link_dynamic_2 *ld_2;
126*7c478bd9Sstevel@tonic-gate } ld_un;
127*7c478bd9Sstevel@tonic-gate };
128*7c478bd9Sstevel@tonic-gate
129*7c478bd9Sstevel@tonic-gate struct old_link_dynamic {
130*7c478bd9Sstevel@tonic-gate int ld_version; /* version # of this structure */
131*7c478bd9Sstevel@tonic-gate union {
132*7c478bd9Sstevel@tonic-gate struct link_dynamic_1 ld_1;
133*7c478bd9Sstevel@tonic-gate } ld_un;
134*7c478bd9Sstevel@tonic-gate
135*7c478bd9Sstevel@tonic-gate int in_debugging;
136*7c478bd9Sstevel@tonic-gate int sym_loaded;
137*7c478bd9Sstevel@tonic-gate char *bp_addr;
138*7c478bd9Sstevel@tonic-gate int bp_inst;
139*7c478bd9Sstevel@tonic-gate struct rtc_symb *cp; /* pointer to an array of runtime */
140*7c478bd9Sstevel@tonic-gate /* allocated common symbols. */
141*7c478bd9Sstevel@tonic-gate };
142*7c478bd9Sstevel@tonic-gate
143*7c478bd9Sstevel@tonic-gate #define v2 ld_un.ld_2 /* short hands */
144*7c478bd9Sstevel@tonic-gate #define v1 ld_un.ld_1
145*7c478bd9Sstevel@tonic-gate
146*7c478bd9Sstevel@tonic-gate /*
147*7c478bd9Sstevel@tonic-gate * SunOS 4.x SPARC relocation types and relocation record. Note that
148*7c478bd9Sstevel@tonic-gate * these, among other things, make this program not portable to things
149*7c478bd9Sstevel@tonic-gate * other than SPARC.
150*7c478bd9Sstevel@tonic-gate */
151*7c478bd9Sstevel@tonic-gate enum reloc_type {
152*7c478bd9Sstevel@tonic-gate RELOC_8, RELOC_16, RELOC_32, /* simplest relocs */
153*7c478bd9Sstevel@tonic-gate RELOC_DISP8, RELOC_DISP16, RELOC_DISP32,
154*7c478bd9Sstevel@tonic-gate /* Disp's (pc-rel) */
155*7c478bd9Sstevel@tonic-gate RELOC_WDISP30, RELOC_WDISP22, /* SR word disp's */
156*7c478bd9Sstevel@tonic-gate RELOC_HI22, RELOC_22, /* SR 22-bit relocs */
157*7c478bd9Sstevel@tonic-gate RELOC_13, RELOC_LO10, /* SR 13&10-bit relocs */
158*7c478bd9Sstevel@tonic-gate RELOC_SFA_BASE, RELOC_SFA_OFF13, /* SR S.F.A. relocs */
159*7c478bd9Sstevel@tonic-gate RELOC_BASE10, RELOC_BASE13, RELOC_BASE22,
160*7c478bd9Sstevel@tonic-gate /* PIC GOT references */
161*7c478bd9Sstevel@tonic-gate RELOC_PC10, RELOC_PC22, /* PIC reference to GOT */
162*7c478bd9Sstevel@tonic-gate RELOC_JMP_TBL, /* PIC call */
163*7c478bd9Sstevel@tonic-gate RELOC_SEGOFF16, /* .so offset-in-segment */
164*7c478bd9Sstevel@tonic-gate RELOC_GLOB_DAT, RELOC_JMP_SLOT, RELOC_RELATIVE,
165*7c478bd9Sstevel@tonic-gate /* ld.so relocation types */
166*7c478bd9Sstevel@tonic-gate };
167*7c478bd9Sstevel@tonic-gate
168*7c478bd9Sstevel@tonic-gate struct relocation_info {
169*7c478bd9Sstevel@tonic-gate unsigned long int r_address; /* relocation addr */
170*7c478bd9Sstevel@tonic-gate unsigned int r_index :24; /* segment index or symbol index */
171*7c478bd9Sstevel@tonic-gate unsigned int r_extern : 1; /* if F, r_index==SEG#; if T, SYM idx */
172*7c478bd9Sstevel@tonic-gate int : 2; /* <unused> */
173*7c478bd9Sstevel@tonic-gate enum reloc_type r_type : 5; /* type of relocation to perform */
174*7c478bd9Sstevel@tonic-gate long int r_addend; /* addend for relocation value */
175*7c478bd9Sstevel@tonic-gate };
176*7c478bd9Sstevel@tonic-gate
177*7c478bd9Sstevel@tonic-gate /*
178*7c478bd9Sstevel@tonic-gate * Size of relocations.
179*7c478bd9Sstevel@tonic-gate */
180*7c478bd9Sstevel@tonic-gate #define GETRELSZ(x) \
181*7c478bd9Sstevel@tonic-gate (x->ld_version < 2 ? \
182*7c478bd9Sstevel@tonic-gate ((struct old_link_dynamic *)x)->v1.ld_hash - \
183*7c478bd9Sstevel@tonic-gate ((struct old_link_dynamic *)x)->v1.ld_rel : \
184*7c478bd9Sstevel@tonic-gate (x)->v2->ld_hash - (x)->v2->ld_rel)
185*7c478bd9Sstevel@tonic-gate
186*7c478bd9Sstevel@tonic-gate /*
187*7c478bd9Sstevel@tonic-gate * Interface between crt0 & ld.so.
188*7c478bd9Sstevel@tonic-gate */
189*7c478bd9Sstevel@tonic-gate struct crt_i1 {
190*7c478bd9Sstevel@tonic-gate int crt_baseaddr; /* Address ld.so is at */
191*7c478bd9Sstevel@tonic-gate int crt_dzfd; /* /dev/zero file descriptor */
192*7c478bd9Sstevel@tonic-gate int crt_rlfd; /* ld.so file descriptor */
193*7c478bd9Sstevel@tonic-gate struct link_dynamic *crt_udp; /* "main_" dynamic */
194*7c478bd9Sstevel@tonic-gate char **crt_ep; /* environment strings */
195*7c478bd9Sstevel@tonic-gate caddr_t crt_breakp; /* place to put initial breakpoint */
196*7c478bd9Sstevel@tonic-gate };
197*7c478bd9Sstevel@tonic-gate
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate * Structure we provide to ELF ld.so upon entry.
200*7c478bd9Sstevel@tonic-gate */
201*7c478bd9Sstevel@tonic-gate Elf32_Boot eb[EB_MAX];
202*7c478bd9Sstevel@tonic-gate
203*7c478bd9Sstevel@tonic-gate /*
204*7c478bd9Sstevel@tonic-gate * Global data.
205*7c478bd9Sstevel@tonic-gate */
206*7c478bd9Sstevel@tonic-gate char *program_name; /* used in messages */
207*7c478bd9Sstevel@tonic-gate
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate * 4.0 ld.so main entry point.
210*7c478bd9Sstevel@tonic-gate */
rtld(version,ip,dp,argp)211*7c478bd9Sstevel@tonic-gate rtld(version, ip, dp, argp)
212*7c478bd9Sstevel@tonic-gate int version; /* interface version */
213*7c478bd9Sstevel@tonic-gate struct crt_i1 *ip; /* interface passed from program */
214*7c478bd9Sstevel@tonic-gate register struct link_dynamic *dp; /* ld.so dynamic pointer */
215*7c478bd9Sstevel@tonic-gate caddr_t argp; /* pointer to begining of args */
216*7c478bd9Sstevel@tonic-gate {
217*7c478bd9Sstevel@tonic-gate char *ldso; /* name of what we really want to be */
218*7c478bd9Sstevel@tonic-gate int i, p; /* working */
219*7c478bd9Sstevel@tonic-gate int r; /* working (# of *our* relocations */
220*7c478bd9Sstevel@tonic-gate int page_size = 0; /* size of a page */
221*7c478bd9Sstevel@tonic-gate struct relocation_info *rp; /* working pointer to our relocs */
222*7c478bd9Sstevel@tonic-gate int fd; /* fd assigned to ld.so */
223*7c478bd9Sstevel@tonic-gate Elf32_Ehdr *ehdr; /* ELF header of ld.so */
224*7c478bd9Sstevel@tonic-gate Elf32_Phdr *phdr; /* first Phdr in file */
225*7c478bd9Sstevel@tonic-gate Elf32_Phdr *pptr; /* working Phdr */
226*7c478bd9Sstevel@tonic-gate Elf32_Phdr *lph; /* last loadable Phdr */
227*7c478bd9Sstevel@tonic-gate Elf32_Phdr *fph = 0; /* first loadable Phdr */
228*7c478bd9Sstevel@tonic-gate caddr_t maddr; /* pointer to mapping claim */
229*7c478bd9Sstevel@tonic-gate Elf32_Off mlen; /* total mapping claim */
230*7c478bd9Sstevel@tonic-gate caddr_t faddr; /* first program mapping of ld.so */
231*7c478bd9Sstevel@tonic-gate Elf32_Off foff; /* file offset for segment mapping */
232*7c478bd9Sstevel@tonic-gate Elf32_Off flen; /* file length for segment mapping */
233*7c478bd9Sstevel@tonic-gate caddr_t addr; /* working mapping address */
234*7c478bd9Sstevel@tonic-gate caddr_t zaddr; /* /dev/zero working mapping addr */
235*7c478bd9Sstevel@tonic-gate Elf32_Boot *ebp; /* communication with ld.so */
236*7c478bd9Sstevel@tonic-gate struct stat sb; /* stat buffer for sizing */
237*7c478bd9Sstevel@tonic-gate auxv_t *ap; /* working aux pointer */
238*7c478bd9Sstevel@tonic-gate void (* wrt)(); /* address of write/iflush routine */
239*7c478bd9Sstevel@tonic-gate
240*7c478bd9Sstevel@tonic-gate /*
241*7c478bd9Sstevel@tonic-gate * ld.so must itself be relocated, take care of this now.
242*7c478bd9Sstevel@tonic-gate * We can not refer to global data before this step is
243*7c478bd9Sstevel@tonic-gate * complete. Perform the relocation by stepping over all
244*7c478bd9Sstevel@tonic-gate * entries in the relocation table and turn them into
245*7c478bd9Sstevel@tonic-gate * absolute addresses. Note that, in order to avoid invoking
246*7c478bd9Sstevel@tonic-gate * as yet unrelocated items, we perform the relocation count
247*7c478bd9Sstevel@tonic-gate * by counting rather than risk invoking subroutine calls
248*7c478bd9Sstevel@tonic-gate * to intrinsic .div or .mul routines. Note also that we
249*7c478bd9Sstevel@tonic-gate * assume that there are no symbolic relocations to be
250*7c478bd9Sstevel@tonic-gate * performed here.
251*7c478bd9Sstevel@tonic-gate */
252*7c478bd9Sstevel@tonic-gate dp->v2 = (struct link_dynamic_2 *)
253*7c478bd9Sstevel@tonic-gate ((caddr_t)dp->v2 + ip->crt_baseaddr);
254*7c478bd9Sstevel@tonic-gate r = 0;
255*7c478bd9Sstevel@tonic-gate i = GETRELSZ(dp);
256*7c478bd9Sstevel@tonic-gate while (i != 0) {
257*7c478bd9Sstevel@tonic-gate i -= RELOC_SIZE;
258*7c478bd9Sstevel@tonic-gate r++;
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate rp = (struct relocation_info *)(RELOCOFF(dp) +
261*7c478bd9Sstevel@tonic-gate (dp->ld_version < DYNAMIC_VERSION2 ?
262*7c478bd9Sstevel@tonic-gate (int)dp : ip->crt_baseaddr));
263*7c478bd9Sstevel@tonic-gate
264*7c478bd9Sstevel@tonic-gate /*
265*7c478bd9Sstevel@tonic-gate * Determine the location of the routine that will write the relocation.
266*7c478bd9Sstevel@tonic-gate * This hasn't yet been relocated so determine the real address using
267*7c478bd9Sstevel@tonic-gate * our base address.
268*7c478bd9Sstevel@tonic-gate */
269*7c478bd9Sstevel@tonic-gate wrt = (void (*)())((caddr_t)aout_reloc_write + ip->crt_baseaddr);
270*7c478bd9Sstevel@tonic-gate
271*7c478bd9Sstevel@tonic-gate /*
272*7c478bd9Sstevel@tonic-gate * Relocate ourselves - we only need RELOC_RELATIVE and RELOC_32.
273*7c478bd9Sstevel@tonic-gate * Note, if panic() was called its probable that it will barf as the
274*7c478bd9Sstevel@tonic-gate * corresponding plt wouldn't have been relocated yet.
275*7c478bd9Sstevel@tonic-gate */
276*7c478bd9Sstevel@tonic-gate for (i = 0; i < r; i++) {
277*7c478bd9Sstevel@tonic-gate long *where = (long *)((caddr_t)rp->r_address + ip->crt_baseaddr);
278*7c478bd9Sstevel@tonic-gate long what = ip->crt_baseaddr;
279*7c478bd9Sstevel@tonic-gate long value;
280*7c478bd9Sstevel@tonic-gate
281*7c478bd9Sstevel@tonic-gate switch (rp->r_type) {
282*7c478bd9Sstevel@tonic-gate case RELOC_RELATIVE:
283*7c478bd9Sstevel@tonic-gate what += *where << (32-22);
284*7c478bd9Sstevel@tonic-gate value = (*where & ~MASK(22)) | ((what >> (32-22)) & MASK(22));
285*7c478bd9Sstevel@tonic-gate wrt(where, value);
286*7c478bd9Sstevel@tonic-gate where++;
287*7c478bd9Sstevel@tonic-gate what += (*where & MASK(10));
288*7c478bd9Sstevel@tonic-gate value = (*where & ~MASK(10)) | (what & MASK(10));
289*7c478bd9Sstevel@tonic-gate wrt(where, value);
290*7c478bd9Sstevel@tonic-gate break;
291*7c478bd9Sstevel@tonic-gate
292*7c478bd9Sstevel@tonic-gate case RELOC_32:
293*7c478bd9Sstevel@tonic-gate what += *where;
294*7c478bd9Sstevel@tonic-gate wrt(where, what);
295*7c478bd9Sstevel@tonic-gate break;
296*7c478bd9Sstevel@tonic-gate
297*7c478bd9Sstevel@tonic-gate default:
298*7c478bd9Sstevel@tonic-gate panic("unknown relocation type %d\n", rp->r_type);
299*7c478bd9Sstevel@tonic-gate break;
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate rp++;
302*7c478bd9Sstevel@tonic-gate }
303*7c478bd9Sstevel@tonic-gate
304*7c478bd9Sstevel@tonic-gate /*
305*7c478bd9Sstevel@tonic-gate * We're relocated, we can now initialize things referencing
306*7c478bd9Sstevel@tonic-gate * static storage.
307*7c478bd9Sstevel@tonic-gate */
308*7c478bd9Sstevel@tonic-gate ldso = "/usr/lib/ld.so.1";
309*7c478bd9Sstevel@tonic-gate
310*7c478bd9Sstevel@tonic-gate /*
311*7c478bd9Sstevel@tonic-gate * Close off the file descriptor used to get us here -- let it
312*7c478bd9Sstevel@tonic-gate * be available for the next (probable) use below.
313*7c478bd9Sstevel@tonic-gate */
314*7c478bd9Sstevel@tonic-gate (void) close(ip->crt_rlfd);
315*7c478bd9Sstevel@tonic-gate
316*7c478bd9Sstevel@tonic-gate /*
317*7c478bd9Sstevel@tonic-gate * Discover things about our environment: auxiliary vector (if
318*7c478bd9Sstevel@tonic-gate * any), arguments, program name, and the like.
319*7c478bd9Sstevel@tonic-gate */
320*7c478bd9Sstevel@tonic-gate ebp = eb;
321*7c478bd9Sstevel@tonic-gate program_name = (char *)(argp + sizeof (int));
322*7c478bd9Sstevel@tonic-gate if (version != 1)
323*7c478bd9Sstevel@tonic-gate panic("bad startup interface version of %d",
324*7c478bd9Sstevel@tonic-gate version);
325*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_DYNAMIC,
326*7c478bd9Sstevel@tonic-gate (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_udp;
327*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_ARGV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)program_name;
328*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_ENVP, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)ip->crt_ep;
329*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_DEVZERO,
330*7c478bd9Sstevel@tonic-gate (ebp++)->eb_un.eb_val = (Elf32_Word)ip->crt_dzfd;
331*7c478bd9Sstevel@tonic-gate for (addr = (caddr_t)ip->crt_ep; *addr; addr += sizeof (char *))
332*7c478bd9Sstevel@tonic-gate ;
333*7c478bd9Sstevel@tonic-gate addr += sizeof (char *);
334*7c478bd9Sstevel@tonic-gate
335*7c478bd9Sstevel@tonic-gate /*
336*7c478bd9Sstevel@tonic-gate * The kernel sends us an abbreviated aux vector with some
337*7c478bd9Sstevel@tonic-gate * potentially handy stuff that saves us on syscalls.
338*7c478bd9Sstevel@tonic-gate *
339*7c478bd9Sstevel@tonic-gate * Notes on 1226113
340*7c478bd9Sstevel@tonic-gate *
341*7c478bd9Sstevel@tonic-gate * The f77 compiler shipped as part of SC1.0 on 4.x creates binaries
342*7c478bd9Sstevel@tonic-gate * that use the _fix_libc_ feature of acc. This makes the resulting
343*7c478bd9Sstevel@tonic-gate * executable object dependent on the undocumented behaviour of
344*7c478bd9Sstevel@tonic-gate * libc's .rem and .div routines e.g. that .div returns the
345*7c478bd9Sstevel@tonic-gate * remainder in %o3 (and similarly .rem returns the division in %o3).
346*7c478bd9Sstevel@tonic-gate *
347*7c478bd9Sstevel@tonic-gate * The only simple solution is to disable hardware divide for
348*7c478bd9Sstevel@tonic-gate * all 4.x applications so that the old software routines that have
349*7c478bd9Sstevel@tonic-gate * this "support" in them are used instead. And we do that by
350*7c478bd9Sstevel@tonic-gate * clearing the divide-in-hardware flag from the aux vector before
351*7c478bd9Sstevel@tonic-gate * libc's .init routine gets to see it. Awful isn't it.
352*7c478bd9Sstevel@tonic-gate */
353*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_AUXV, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)addr;
354*7c478bd9Sstevel@tonic-gate for (ap = (auxv_t *)addr; ap->a_type != AT_NULL; ap++)
355*7c478bd9Sstevel@tonic-gate if (ap->a_type == AT_PAGESZ) {
356*7c478bd9Sstevel@tonic-gate page_size = ap->a_un.a_val;
357*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
358*7c478bd9Sstevel@tonic-gate (Elf32_Word)page_size;
359*7c478bd9Sstevel@tonic-gate } else if (ap->a_type == AT_SUN_HWCAP)
360*7c478bd9Sstevel@tonic-gate ap->a_un.a_val &= ~AV_SPARC_HWDIV_32x32;
361*7c478bd9Sstevel@tonic-gate
362*7c478bd9Sstevel@tonic-gate /*
363*7c478bd9Sstevel@tonic-gate * If we didn't get a page size from looking in the auxiliary
364*7c478bd9Sstevel@tonic-gate * vector, we need to get one now.
365*7c478bd9Sstevel@tonic-gate */
366*7c478bd9Sstevel@tonic-gate if (page_size == 0) {
367*7c478bd9Sstevel@tonic-gate page_size = sysconfig(_CONFIG_PAGESIZE);
368*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
369*7c478bd9Sstevel@tonic-gate (Elf32_Word)page_size;
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate * Map in the ELF-based ld.so. Note that we're mapping it as
374*7c478bd9Sstevel@tonic-gate * an ELF database, not as a program -- we just want to walk it's
375*7c478bd9Sstevel@tonic-gate * data structures. Further mappings will actually establish the
376*7c478bd9Sstevel@tonic-gate * program in the address space.
377*7c478bd9Sstevel@tonic-gate */
378*7c478bd9Sstevel@tonic-gate if ((fd = open(ldso, O_RDONLY)) == -1)
379*7c478bd9Sstevel@tonic-gate panic("unable to open %s", ldso);
380*7c478bd9Sstevel@tonic-gate if (fstat(fd, &sb) == -1)
381*7c478bd9Sstevel@tonic-gate panic("unable to find size of %s", ldso);
382*7c478bd9Sstevel@tonic-gate ehdr = (Elf32_Ehdr *)mmap(0, sb.st_size, PROT_READ | PROT_EXEC,
383*7c478bd9Sstevel@tonic-gate MAP_SHARED, fd, 0);
384*7c478bd9Sstevel@tonic-gate if (ehdr == (Elf32_Ehdr *)-1)
385*7c478bd9Sstevel@tonic-gate panic("unable to map %s", ldso);
386*7c478bd9Sstevel@tonic-gate
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate * Validate the file we're looking at, ensure it has the correct
389*7c478bd9Sstevel@tonic-gate * ELF structures, such as: ELF magic numbers, coded for SPARC,
390*7c478bd9Sstevel@tonic-gate * is a ".so", etc.
391*7c478bd9Sstevel@tonic-gate */
392*7c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
393*7c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
394*7c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
395*7c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_MAG3] != ELFMAG3)
396*7c478bd9Sstevel@tonic-gate panic("%s is not an ELF file", ldso);
397*7c478bd9Sstevel@tonic-gate if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
398*7c478bd9Sstevel@tonic-gate ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
399*7c478bd9Sstevel@tonic-gate panic("%s has wrong class or data encoding", ldso);
400*7c478bd9Sstevel@tonic-gate if (ehdr->e_type != ET_DYN)
401*7c478bd9Sstevel@tonic-gate panic("%s is not a shared object", ldso);
402*7c478bd9Sstevel@tonic-gate if ((ehdr->e_machine != EM_SPARC) &&
403*7c478bd9Sstevel@tonic-gate (ehdr->e_machine != EM_SPARC32PLUS))
404*7c478bd9Sstevel@tonic-gate panic("%s is not a valid SPARC object: e_machine: %x",
405*7c478bd9Sstevel@tonic-gate ldso, ehdr->e_machine);
406*7c478bd9Sstevel@tonic-gate if (ehdr->e_version > EV_CURRENT)
407*7c478bd9Sstevel@tonic-gate panic("%s has bad ELF version of %d", ldso, ehdr->e_version);
408*7c478bd9Sstevel@tonic-gate
409*7c478bd9Sstevel@tonic-gate /*
410*7c478bd9Sstevel@tonic-gate * Point at program headers and start figuring out what to load.
411*7c478bd9Sstevel@tonic-gate */
412*7c478bd9Sstevel@tonic-gate phdr = (Elf32_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
413*7c478bd9Sstevel@tonic-gate for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
414*7c478bd9Sstevel@tonic-gate pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize))
415*7c478bd9Sstevel@tonic-gate if (pptr->p_type == PT_LOAD) {
416*7c478bd9Sstevel@tonic-gate if (fph == 0) {
417*7c478bd9Sstevel@tonic-gate fph = pptr;
418*7c478bd9Sstevel@tonic-gate } else if (pptr->p_vaddr <= lph->p_vaddr)
419*7c478bd9Sstevel@tonic-gate panic(
420*7c478bd9Sstevel@tonic-gate "%s invalid program header - segments out of order", ldso);
421*7c478bd9Sstevel@tonic-gate lph = pptr;
422*7c478bd9Sstevel@tonic-gate }
423*7c478bd9Sstevel@tonic-gate
424*7c478bd9Sstevel@tonic-gate /*
425*7c478bd9Sstevel@tonic-gate * We'd better have at least one loadable segment.
426*7c478bd9Sstevel@tonic-gate */
427*7c478bd9Sstevel@tonic-gate if (fph == 0)
428*7c478bd9Sstevel@tonic-gate panic("%s has no loadable segments", ldso);
429*7c478bd9Sstevel@tonic-gate
430*7c478bd9Sstevel@tonic-gate /*
431*7c478bd9Sstevel@tonic-gate * Map enough address space to hold the program (as opposed to the
432*7c478bd9Sstevel@tonic-gate * file) represented by ld.so. The amount to be assigned is the
433*7c478bd9Sstevel@tonic-gate * range between the end of the last loadable segment and the
434*7c478bd9Sstevel@tonic-gate * beginning of the first PLUS the alignment of the first segment.
435*7c478bd9Sstevel@tonic-gate * mmap() can assign us any page-aligned address, but the relocations
436*7c478bd9Sstevel@tonic-gate * assume the alignments included in the program header. As an
437*7c478bd9Sstevel@tonic-gate * optimization, however, let's assume that mmap() will actually
438*7c478bd9Sstevel@tonic-gate * give us an aligned address -- since if it does, we can save
439*7c478bd9Sstevel@tonic-gate * an munmap() later on. If it doesn't -- then go try it again.
440*7c478bd9Sstevel@tonic-gate */
441*7c478bd9Sstevel@tonic-gate mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
442*7c478bd9Sstevel@tonic-gate ALIGN(fph->p_vaddr, page_size), page_size);
443*7c478bd9Sstevel@tonic-gate maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC,
444*7c478bd9Sstevel@tonic-gate MAP_SHARED, fd, 0);
445*7c478bd9Sstevel@tonic-gate if (maddr == (caddr_t)-1)
446*7c478bd9Sstevel@tonic-gate panic("unable to reserve space for %s", ldso);
447*7c478bd9Sstevel@tonic-gate faddr = (caddr_t)ROUND(maddr, fph->p_align);
448*7c478bd9Sstevel@tonic-gate
449*7c478bd9Sstevel@tonic-gate /*
450*7c478bd9Sstevel@tonic-gate * Check to see whether alignment skew was really needed.
451*7c478bd9Sstevel@tonic-gate */
452*7c478bd9Sstevel@tonic-gate if (faddr != maddr) {
453*7c478bd9Sstevel@tonic-gate (void) munmap(maddr, mlen);
454*7c478bd9Sstevel@tonic-gate mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
455*7c478bd9Sstevel@tonic-gate ALIGN(fph->p_vaddr, fph->p_align) + fph->p_align,
456*7c478bd9Sstevel@tonic-gate page_size);
457*7c478bd9Sstevel@tonic-gate maddr = (caddr_t)mmap(0, mlen, PROT_READ | PROT_EXEC,
458*7c478bd9Sstevel@tonic-gate MAP_SHARED, fd, 0);
459*7c478bd9Sstevel@tonic-gate if (maddr == (caddr_t)-1)
460*7c478bd9Sstevel@tonic-gate panic("unable to reserve space for %s", ldso);
461*7c478bd9Sstevel@tonic-gate faddr = (caddr_t)ROUND(maddr, fph->p_align);
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_LDSO_BASE, (ebp++)->eb_un.eb_ptr = (Elf32_Addr)faddr;
464*7c478bd9Sstevel@tonic-gate
465*7c478bd9Sstevel@tonic-gate /*
466*7c478bd9Sstevel@tonic-gate * We have the address space reserved, so map each loadable segment.
467*7c478bd9Sstevel@tonic-gate */
468*7c478bd9Sstevel@tonic-gate for (pptr = phdr; (pptr - phdr) < (int)ehdr->e_phnum; pptr++) {
469*7c478bd9Sstevel@tonic-gate
470*7c478bd9Sstevel@tonic-gate /*
471*7c478bd9Sstevel@tonic-gate * Skip non-loadable segments or segments that don't occupy
472*7c478bd9Sstevel@tonic-gate * any memory.
473*7c478bd9Sstevel@tonic-gate */
474*7c478bd9Sstevel@tonic-gate if ((pptr->p_type != PT_LOAD) || (pptr->p_memsz == 0))
475*7c478bd9Sstevel@tonic-gate continue;
476*7c478bd9Sstevel@tonic-gate
477*7c478bd9Sstevel@tonic-gate /*
478*7c478bd9Sstevel@tonic-gate * Determine the file offset to which the mapping will
479*7c478bd9Sstevel@tonic-gate * directed (must be aligned) and how much to map (might
480*7c478bd9Sstevel@tonic-gate * be more than the file in the case of .bss.)
481*7c478bd9Sstevel@tonic-gate */
482*7c478bd9Sstevel@tonic-gate foff = ALIGN(pptr->p_offset, page_size);
483*7c478bd9Sstevel@tonic-gate flen = pptr->p_memsz + (pptr->p_offset - foff);
484*7c478bd9Sstevel@tonic-gate
485*7c478bd9Sstevel@tonic-gate /*
486*7c478bd9Sstevel@tonic-gate * Set address of this segment relative to our base.
487*7c478bd9Sstevel@tonic-gate */
488*7c478bd9Sstevel@tonic-gate addr = (caddr_t)ALIGN(faddr + pptr->p_vaddr, page_size);
489*7c478bd9Sstevel@tonic-gate
490*7c478bd9Sstevel@tonic-gate /*
491*7c478bd9Sstevel@tonic-gate * Unmap anything form the last mapping address to this
492*7c478bd9Sstevel@tonic-gate * one.
493*7c478bd9Sstevel@tonic-gate */
494*7c478bd9Sstevel@tonic-gate if (addr - maddr) {
495*7c478bd9Sstevel@tonic-gate (void) munmap(maddr, addr - maddr);
496*7c478bd9Sstevel@tonic-gate mlen -= addr - maddr;
497*7c478bd9Sstevel@tonic-gate }
498*7c478bd9Sstevel@tonic-gate
499*7c478bd9Sstevel@tonic-gate /*
500*7c478bd9Sstevel@tonic-gate * Determine the mapping protection from the section
501*7c478bd9Sstevel@tonic-gate * attributes.
502*7c478bd9Sstevel@tonic-gate */
503*7c478bd9Sstevel@tonic-gate i = 0;
504*7c478bd9Sstevel@tonic-gate if (pptr->p_flags & PF_R)
505*7c478bd9Sstevel@tonic-gate i |= PROT_READ;
506*7c478bd9Sstevel@tonic-gate if (pptr->p_flags & PF_W)
507*7c478bd9Sstevel@tonic-gate i |= PROT_WRITE;
508*7c478bd9Sstevel@tonic-gate if (pptr->p_flags & PF_X)
509*7c478bd9Sstevel@tonic-gate i |= PROT_EXEC;
510*7c478bd9Sstevel@tonic-gate if ((caddr_t)mmap((caddr_t)addr, flen, i,
511*7c478bd9Sstevel@tonic-gate MAP_FIXED | MAP_PRIVATE, fd, foff) == (caddr_t)-1)
512*7c478bd9Sstevel@tonic-gate panic("unable to map a segment from %s", ldso);
513*7c478bd9Sstevel@tonic-gate
514*7c478bd9Sstevel@tonic-gate /*
515*7c478bd9Sstevel@tonic-gate * If the memory occupancy of the segment overflows the
516*7c478bd9Sstevel@tonic-gate * definition in the file, we need to "zero out" the
517*7c478bd9Sstevel@tonic-gate * end of the mapping we've established, and if necessary,
518*7c478bd9Sstevel@tonic-gate * map some more space from /dev/zero.
519*7c478bd9Sstevel@tonic-gate */
520*7c478bd9Sstevel@tonic-gate if (pptr->p_memsz > pptr->p_filesz) {
521*7c478bd9Sstevel@tonic-gate foff = (int)faddr + pptr->p_vaddr + pptr->p_filesz;
522*7c478bd9Sstevel@tonic-gate zaddr = (caddr_t)ROUND(foff, page_size);
523*7c478bd9Sstevel@tonic-gate _zero(foff, zaddr - foff);
524*7c478bd9Sstevel@tonic-gate r = (faddr + pptr->p_vaddr + pptr->p_memsz) - zaddr;
525*7c478bd9Sstevel@tonic-gate if (r > 0)
526*7c478bd9Sstevel@tonic-gate if ((caddr_t)mmap((caddr_t)zaddr, r, i,
527*7c478bd9Sstevel@tonic-gate MAP_FIXED | MAP_PRIVATE, ip->crt_dzfd,
528*7c478bd9Sstevel@tonic-gate 0) == (caddr_t)-1)
529*7c478bd9Sstevel@tonic-gate panic(
530*7c478bd9Sstevel@tonic-gate "unable to map .bss /dev/zero for %s",
531*7c478bd9Sstevel@tonic-gate ldso);
532*7c478bd9Sstevel@tonic-gate }
533*7c478bd9Sstevel@tonic-gate
534*7c478bd9Sstevel@tonic-gate /*
535*7c478bd9Sstevel@tonic-gate * Update the mapping claim pointer.
536*7c478bd9Sstevel@tonic-gate */
537*7c478bd9Sstevel@tonic-gate maddr = addr + ROUND(flen, page_size);
538*7c478bd9Sstevel@tonic-gate mlen -= maddr - addr;
539*7c478bd9Sstevel@tonic-gate }
540*7c478bd9Sstevel@tonic-gate
541*7c478bd9Sstevel@tonic-gate /*
542*7c478bd9Sstevel@tonic-gate * Unmap any final reservation.
543*7c478bd9Sstevel@tonic-gate */
544*7c478bd9Sstevel@tonic-gate if (mlen > 0)
545*7c478bd9Sstevel@tonic-gate (void) munmap(maddr, mlen);
546*7c478bd9Sstevel@tonic-gate
547*7c478bd9Sstevel@tonic-gate /*
548*7c478bd9Sstevel@tonic-gate * Clean up file descriptor space we've consumed. Pass along
549*7c478bd9Sstevel@tonic-gate * the /dev/zero file descriptor we got -- every cycle counts.
550*7c478bd9Sstevel@tonic-gate */
551*7c478bd9Sstevel@tonic-gate (void) close(fd);
552*7c478bd9Sstevel@tonic-gate
553*7c478bd9Sstevel@tonic-gate /*
554*7c478bd9Sstevel@tonic-gate * The call itself. Note that we start 1 instruction word in.
555*7c478bd9Sstevel@tonic-gate * The ELF ld.so contains an "entry vector" of branch instructions,
556*7c478bd9Sstevel@tonic-gate * which, for our interest are:
557*7c478bd9Sstevel@tonic-gate * +0: ba, a <normal startup>
558*7c478bd9Sstevel@tonic-gate * +4: ba, a <compatibility startup>
559*7c478bd9Sstevel@tonic-gate * By starting at the compatibility startup, the ELF ld.so knows
560*7c478bd9Sstevel@tonic-gate * that a pointer to "eb" is available to it and further knows
561*7c478bd9Sstevel@tonic-gate * how to calculate the offset to the program's arguments and
562*7c478bd9Sstevel@tonic-gate * other structures.
563*7c478bd9Sstevel@tonic-gate */
564*7c478bd9Sstevel@tonic-gate ebp->eb_tag = EB_NULL, ebp->eb_un.eb_val = 0;
565*7c478bd9Sstevel@tonic-gate (*((void (*)())(ehdr->e_entry + faddr + sizeof (long))))(eb);
566*7c478bd9Sstevel@tonic-gate return (0);
567*7c478bd9Sstevel@tonic-gate }
568