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