1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 */ 31 32 /* 33 * SPARC machine dependent and a.out format file class dependent functions. 34 * Contains routines for performing function binding and symbol relocations. 35 */ 36 37 #include <stdio.h> 38 #include <sys/types.h> 39 #include <sys/mman.h> 40 #include <synch.h> 41 #include <dlfcn.h> 42 #include <debug.h> 43 #include "_a.out.h" 44 #include "_rtld.h" 45 #include "_audit.h" 46 #include "msg.h" 47 48 extern void iflush_range(caddr_t, size_t); 49 50 /* 51 * Function binding routine - invoked on the first call to a function through 52 * the procedure linkage table; 53 * passes first through an assembly language interface. 54 * 55 * Takes the address of the PLT entry where the call originated, 56 * the offset into the relocation table of the associated 57 * relocation entry and the address of the link map (rt_private_map struct) 58 * for the entry. 59 * 60 * Returns the address of the function referenced after re-writing the PLT 61 * entry to invoke the function directly. 62 * 63 * On error, causes process to terminate with a signal. 64 */ 65 ulong_t 66 aout_bndr(caddr_t pc) 67 { 68 Rt_map *lmp, *nlmp, *llmp; 69 struct relocation_info *rp; 70 struct nlist *sp; 71 Sym *sym; 72 char *name; 73 int rndx, entry; 74 ulong_t symval; 75 Slookup sl; 76 uint_t binfo; 77 Lm_list *lml; 78 79 /* 80 * For compatibility with libthread (TI_VERSION 1) we track the entry 81 * value. A zero value indicates we have recursed into ld.so.1 to 82 * further process a locking request (see comments in completion()). 83 * Under this recursion we disable tsort and cleanup activities. 84 */ 85 entry = enter(0); 86 87 for (lmp = lml_main.lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) { 88 if (FCT(lmp) == &aout_fct) { 89 if (pc > (caddr_t)(LM2LP(lmp)->lp_plt) && 90 pc < (caddr_t)((int)LM2LP(lmp)->lp_plt + 91 AOUTDYN(lmp)->v2->ld_plt_sz)) { 92 break; 93 } 94 } 95 } 96 97 #define LAST22BITS 0x3fffff 98 99 /* LINTED */ 100 rndx = *(int *)(pc + (sizeof (ulong_t *) * 2)) & LAST22BITS; 101 rp = &LM2LP(lmp)->lp_rp[rndx]; 102 sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum]; 103 name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; 104 105 /* 106 * Determine the last link-map of this list, this'll be the starting 107 * point for any tsort() processing. 108 */ 109 lml = LIST(lmp); 110 llmp = lml->lm_tail; 111 112 /* 113 * Find definition for symbol. Initialize the symbol lookup data 114 * structure. 115 */ 116 SLOOKUP_INIT(sl, name, lmp, lml->lm_head, ld_entry_cnt, 0, 0, 0, 0, 117 LKUP_DEFT); 118 119 if ((sym = aout_lookup_sym(&sl, &nlmp, &binfo, NULL)) == 0) { 120 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 121 demangle(name)); 122 rtldexit(lml, 1); 123 } 124 125 symval = sym->st_value; 126 if (!(FLAGS(nlmp) & FLG_RT_FIXED) && 127 (sym->st_shndx != SHN_ABS)) 128 symval += (int)(ADDR(nlmp)); 129 if ((lmp != nlmp) && ((FLAGS1(nlmp) & FL1_RT_NOINIFIN) == 0)) { 130 /* 131 * Record that this new link map is now bound to the caller. 132 */ 133 if (bind_one(lmp, nlmp, BND_REFER) == 0) 134 rtldexit(lml, 1); 135 } 136 137 /* 138 * Print binding information and rebuild PLT entry. 139 */ 140 DBG_CALL(Dbg_bind_global(lmp, (Addr)(ADDR(lmp) + rp->r_address), 141 (Off)rp->r_address, (Xword)(-1), PLT_T_NONE, nlmp, 142 (Addr)symval, sym->st_value, name, binfo)); 143 144 if (!(rtld_flags & RT_FL_NOBIND)) 145 aout_plt_write((caddr_t)(ADDR(lmp) + rp->r_address), symval); 146 147 /* 148 * Complete any processing for newly loaded objects. Note we don't 149 * know exactly where any new objects are loaded (we know the object 150 * that supplied the symbol, but others may have been loaded lazily as 151 * we searched for the symbol), so sorting starts from the last 152 * link-map know on entry to this routine. 153 */ 154 if (entry) 155 load_completion(llmp); 156 157 /* 158 * If the object we've bound to is in the process of being initialized 159 * by another thread, determine whether we should block. 160 */ 161 is_dep_ready(nlmp, lmp, DBG_WAIT_SYMBOL); 162 163 /* 164 * Make sure the object to which we've bound has had it's .init fired. 165 * Cleanup before return to user code. 166 */ 167 if (entry) { 168 is_dep_init(nlmp, lmp); 169 leave(lml, 0); 170 } 171 172 return (symval); 173 } 174 175 176 #define IS_PC_RELATIVE(X) (pc_rel_type[(X)] == 1) 177 178 static const uchar_t pc_rel_type[] = { 179 0, /* RELOC_8 */ 180 0, /* RELOC_16 */ 181 0, /* RELOC_32 */ 182 1, /* RELOC_DISP8 */ 183 1, /* RELOC_DISP16 */ 184 1, /* RELOC_DISP32 */ 185 1, /* RELOC_WDISP30 */ 186 1, /* RELOC_WDISP22 */ 187 0, /* RELOC_HI22 */ 188 0, /* RELOC_22 */ 189 0, /* RELOC_13 */ 190 0, /* RELOC_LO10 */ 191 0, /* RELOC_SFA_BASE */ 192 0, /* RELOC_SFA_OFF13 */ 193 0, /* RELOC_BASE10 */ 194 0, /* RELOC_BASE13 */ 195 0, /* RELOC_BASE22 */ 196 0, /* RELOC_PC10 */ 197 0, /* RELOC_PC22 */ 198 0, /* RELOC_JMP_TBL */ 199 0, /* RELOC_SEGOFF16 */ 200 0, /* RELOC_GLOB_DAT */ 201 0, /* RELOC_JMP_SLOT */ 202 0 /* RELOC_RELATIVE */ 203 }; 204 205 int 206 aout_reloc(Rt_map * lmp, uint_t plt, int *in_nfavl) 207 { 208 int k; /* loop temporary */ 209 int nr; /* number of relocations */ 210 char *name; /* symbol being searched for */ 211 long *et; /* cached _etext of object */ 212 long value; /* relocation temporary */ 213 long *ra; /* cached relocation address */ 214 struct relocation_info *rp; /* current relocation */ 215 struct nlist *sp; /* symbol table of "symbol" */ 216 Rt_map * _lmp; /* lm which holds symbol definition */ 217 Sym * sym; /* symbol definition */ 218 int textrel = 0, ret = 1; 219 APlist *bound = NULL; 220 Lm_list *lml = LIST(lmp); 221 222 DBG_CALL(Dbg_reloc_run(lmp, SHT_RELA, plt, DBG_REL_START)); 223 224 /* 225 * If we've been called upon to promote an RTLD_LAZY object to an 226 * RTLD_NOW don't bother to do anything - a.out's are bound as if 227 * RTLD_NOW regardless. 228 */ 229 if (plt) 230 return (1); 231 232 rp = LM2LP(lmp)->lp_rp; 233 et = (long *)ETEXT(lmp); 234 nr = GETRELSZ(AOUTDYN(lmp)) / sizeof (struct relocation_info); 235 236 /* 237 * Initialize _PLT_, if any. 238 */ 239 if (AOUTDYN(lmp)->v2->ld_plt_sz) 240 aout_plt_write((caddr_t)LM2LP(lmp)->lp_plt->jb_inst, 241 (ulong_t)aout_rtbndr); 242 243 /* 244 * Loop through relocations. 245 */ 246 for (k = 0; k < nr; k++, rp++) { 247 /* LINTED */ 248 ra = (long *)&((char *)ADDR(lmp))[rp->r_address]; 249 250 /* 251 * Check to see if we're relocating in the text segment 252 * and turn off the write protect if necessary. 253 */ 254 if ((ra < et) && (textrel == 0)) { 255 if (aout_set_prot(lmp, PROT_WRITE) == 0) { 256 ret = 0; 257 break; 258 } 259 textrel = 1; 260 } 261 262 /* 263 * Perform the relocation. 264 */ 265 if (rp->r_extern == 0) { 266 name = (char *)0; 267 value = ADDR(lmp); 268 } else { 269 Slookup sl; 270 uint_t binfo; 271 272 if (rp->r_type == RELOC_JMP_SLOT) 273 continue; 274 sp = &LM2LP(lmp)->lp_symtab[rp->r_symbolnum]; 275 name = &LM2LP(lmp)->lp_symstr[sp->n_un.n_strx]; 276 277 /* 278 * Locate symbol. Initialize the symbol lookup data 279 * structure. 280 */ 281 SLOOKUP_INIT(sl, name, lmp, 0, ld_entry_cnt, 0, 0, 0, 0, 282 LKUP_STDRELOC); 283 284 if ((sym = aout_lookup_sym(&sl, &_lmp, 285 &binfo, in_nfavl)) == 0) { 286 if (lml->lm_flags & LML_FLG_TRC_WARN) { 287 (void) 288 printf(MSG_INTL(MSG_LDD_SYM_NFOUND), 289 demangle(name), NAME(lmp)); 290 continue; 291 } else { 292 eprintf(lml, ERR_FATAL, 293 MSG_INTL(MSG_REL_NOSYM), NAME(lmp), 294 demangle(name)); 295 ret = 0; 296 break; 297 } 298 } 299 300 /* 301 * If symbol was found in an object other than the 302 * referencing object then record the binding. 303 */ 304 if ((lmp != _lmp) && 305 ((FLAGS1(_lmp) & FL1_RT_NOINIFIN) == 0)) { 306 if (aplist_test(&bound, _lmp, 307 AL_CNT_RELBIND) == 0) { 308 ret = 0; 309 break; 310 } 311 } 312 313 value = sym->st_value + rp->r_addend; 314 if (!(FLAGS(_lmp) & FLG_RT_FIXED) && 315 (sym->st_shndx != SHN_COMMON) && 316 (sym->st_shndx != SHN_ABS)) 317 value += ADDR(_lmp); 318 319 if (IS_PC_RELATIVE(rp->r_type)) 320 value -= (long)ADDR(lmp); 321 322 DBG_CALL(Dbg_bind_global(lmp, (Addr)ra, 323 (Off)(ra - ADDR(lmp)), (Xword)(-1), PLT_T_NONE, 324 _lmp, (Addr)value, sym->st_value, name, binfo)); 325 } 326 327 /* 328 * Perform a specific relocation operation. 329 */ 330 switch (rp->r_type) { 331 case RELOC_RELATIVE: 332 value += *ra << (32-22); 333 *(long *)ra = (*(long *)ra & ~S_MASK(22)) | 334 ((value >> (32 - 22)) & S_MASK(22)); 335 ra++; 336 value += (*ra & S_MASK(10)); 337 *(long *)ra = (*(long *)ra & ~S_MASK(10)) | 338 (value & S_MASK(10)); 339 break; 340 case RELOC_8: 341 case RELOC_DISP8: 342 value += *ra & S_MASK(8); 343 if (!S_INRANGE(value, 8)) { 344 eprintf(lml, ERR_FATAL, 345 MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp), 346 (name ? demangle(name) : 347 MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 8, 348 (uint_t)ra); 349 } 350 *ra = value; 351 break; 352 case RELOC_LO10: 353 case RELOC_BASE10: 354 value += *ra & S_MASK(10); 355 *(long *)ra = (*(long *)ra & ~S_MASK(10)) | 356 (value & S_MASK(10)); 357 break; 358 case RELOC_BASE13: 359 case RELOC_13: 360 value += *ra & S_MASK(13); 361 *(long *)ra = (*(long *)ra & ~S_MASK(13)) | 362 (value & S_MASK(13)); 363 break; 364 case RELOC_16: 365 case RELOC_DISP16: 366 value += *ra & S_MASK(16); 367 if (!S_INRANGE(value, 16)) { 368 eprintf(lml, ERR_FATAL, 369 MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp), 370 (name ? demangle(name) : 371 MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 16, 372 (uint_t)ra); 373 } 374 *(short *)ra = value; 375 break; 376 case RELOC_22: 377 case RELOC_BASE22: 378 value += *ra & S_MASK(22); 379 if (!S_INRANGE(value, 22)) { 380 eprintf(lml, ERR_FATAL, 381 MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp), 382 (name ? demangle(name) : 383 MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22, 384 (uint_t)ra); 385 } 386 *(long *)ra = (*(long *)ra & ~S_MASK(22)) | 387 (value & S_MASK(22)); 388 break; 389 case RELOC_HI22: 390 value += (*ra & S_MASK(22)) << (32 - 22); 391 *(long *)ra = (*(long *)ra & ~S_MASK(22)) | 392 ((value >> (32 - 22)) & S_MASK(22)); 393 break; 394 case RELOC_WDISP22: 395 value += *ra & S_MASK(22); 396 value >>= 2; 397 if (!S_INRANGE(value, 22)) { 398 eprintf(lml, ERR_FATAL, 399 MSG_INTL(MSG_REL_OVERFLOW), NAME(lmp), 400 (name ? demangle(name) : 401 MSG_INTL(MSG_STR_UNKNOWN)), (int)value, 22, 402 (uint_t)ra); 403 } 404 *(long *)ra = (*(long *)ra & ~S_MASK(22)) | 405 (value & S_MASK(22)); 406 break; 407 case RELOC_WDISP30: 408 value += *ra & S_MASK(30); 409 value >>= 2; 410 *(long *)ra = (*(long *)ra & ~S_MASK(30)) | 411 (value & S_MASK(30)); 412 break; 413 case RELOC_32: 414 case RELOC_GLOB_DAT: 415 case RELOC_DISP32: 416 value += *ra; 417 *(long *)ra = value; 418 break; 419 default: 420 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_REL_UNIMPL), 421 NAME(lmp), (name ? demangle(name) : 422 MSG_INTL(MSG_STR_UNKNOWN)), rp->r_type); 423 ret = 0; 424 break; 425 } 426 427 /* 428 * If this relocation is against a text segment we must make 429 * sure that the instruction cache is flushed. 430 */ 431 if (textrel) { 432 if (rp->r_type == RELOC_RELATIVE) 433 iflush_range((caddr_t)(ra - 1), 0x8); 434 else 435 iflush_range((caddr_t)ra, 0x4); 436 } 437 } 438 439 return (relocate_finish(lmp, bound, textrel, ret)); 440 } 441