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