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 */ 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