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