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