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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <libelf.h> 29 #include <dlfcn.h> 30 #include "machdep.h" 31 #include "reloc.h" 32 #include "msg.h" 33 #include "_librtld.h" 34 #include "alist.h" 35 36 static const char *unknown = 0; /* Stash MSG_INTL(MSG_STR_UNKNOWN) */ 37 38 /* 39 * Process all relocation records. A new `Reloc' structure is allocated to 40 * cache the processing decisions deduced, and these will be applied during 41 * update_reloc(). 42 * A count of the number of null relocations (i.e., relocations that will be 43 * fixed and whoes records will be nulled out), data and function relocations 44 * is maintained. This allows the relocation records themselves to be 45 * rearranged (localized) later if necessary. Note that the number of function 46 * relocations, although coounted, shouldn't differ from the original file, 47 * the index of a .plt must be maintained to the index of its relocation record 48 * within the associated relocation section. 49 * 50 * The intention behind this file is to maintain as much relocation logic as 51 * possible in a generic form. 52 */ 53 int 54 count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr, 55 Xword *null, Xword *data, Xword *func, Alist *nodirect) 56 { 57 Rel *rel; 58 Reloc *reloc; 59 Shdr *shdr; 60 Xword ent, cnt, _cnt; 61 Sym *syms; 62 const char *strs; 63 Cache *__cache; 64 Xword pltndx = 0; 65 66 /* 67 * Determine the number of relocation entries we'll be dealing with. 68 */ 69 shdr = _cache->c_shdr; 70 rel = (Rel *)_cache->c_data->d_buf; 71 ent = shdr->sh_entsize; 72 cnt = shdr->sh_size / ent; 73 74 /* 75 * Allocate a relocation structure for this relocation section. 76 */ 77 if ((reloc = calloc(cnt, sizeof (Reloc))) == 0) 78 return (1); 79 _cache->c_info = (void *)reloc; 80 81 /* 82 * Determine the relocations associated symbol and string table. 83 */ 84 __cache = &cache[shdr->sh_link]; 85 syms = (Sym *)__cache->c_data->d_buf; 86 shdr = __cache->c_shdr; 87 __cache = &cache[shdr->sh_link]; 88 strs = (const char *)__cache->c_data->d_buf; 89 90 /* 91 * Loop through the relocation table. 92 */ 93 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++, 94 rel = (Rel *)((uintptr_t)rel + ent)) { 95 const char *name; 96 /* LINTED */ 97 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH); 98 uchar_t bind; 99 ulong_t offset = rel->r_offset + addr; 100 Rt_map *_lmp; 101 int _bound, _weak; 102 ulong_t rsymndx = ELF_R_SYM(rel->r_info); 103 Slookup sl; 104 uint_t binfo; 105 Sym *_sym, *sym = (syms + rsymndx); 106 107 if (type == M_R_JMP_SLOT) 108 reloc->r_pltndx = ++pltndx; 109 110 /* 111 * Analyze the case where no relocations are to be applied. 112 */ 113 if ((flags & RTLD_REL_ALL) == 0) { 114 /* 115 * Don't apply any relocations to the new image but 116 * insure their offsets are incremented to reflect any 117 * new fixed address. 118 */ 119 reloc->r_flags = FLG_R_INC; 120 121 /* 122 * Undo any relocations that might have already been 123 * applied to the memory image. 124 */ 125 if (flags & RTLD_MEMORY) { 126 reloc->r_flags |= FLG_R_UNDO; 127 128 /* 129 * If a copy relocation is involved we'll need 130 * to know the size of the copy. 131 */ 132 if (type == M_R_COPY) 133 reloc->r_size = sym->st_size; 134 else 135 reloc->r_size = 0; 136 } 137 138 /* 139 * Save the objects new address. 140 */ 141 reloc->r_value = addr; 142 143 if (type == M_R_JMP_SLOT) 144 (*func)++; 145 else 146 (*data)++; 147 continue; 148 } 149 150 /* 151 * Determine the symbol binding of the relocation. Don't assume 152 * that relative relocations are simply M_R_RELATIVE. Although 153 * a pic generated shared object can normally be viewed as 154 * having relative and non-relative relocations, a non-pic 155 * shared object will contain a number of relocations against 156 * local symbols (normally sections). If a relocation is 157 * against a local symbol it qualifies as a relative relocation. 158 */ 159 if ((type == M_R_RELATIVE) || (type == M_R_NONE) || 160 (ELF_ST_BIND(sym->st_info) == STB_LOCAL)) 161 bind = STB_LOCAL; 162 else 163 bind = STB_GLOBAL; 164 165 /* 166 * Analyze the case where only relative relocations are to be 167 * applied. 168 */ 169 if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) { 170 if (flags & RTLD_MEMORY) { 171 if (bind == STB_LOCAL) { 172 /* 173 * Save the relative relocations from 174 * the memory image. The data itself 175 * might already have been relocated, 176 * thus clear the relocation record so 177 * that it will not be performed again. 178 */ 179 reloc->r_flags = FLG_R_CLR; 180 (*null)++; 181 } else { 182 /* 183 * Any non-relative relocation must be 184 * undone, and the relocation records 185 * offset updated to any new fixed 186 * address. 187 */ 188 reloc->r_flags = 189 (FLG_R_UNDO | FLG_R_INC); 190 reloc->r_value = addr; 191 if (type == M_R_JMP_SLOT) 192 (*func)++; 193 else 194 (*data)++; 195 } 196 } else { 197 if (bind == STB_LOCAL) { 198 /* 199 * Apply relative relocation to the 200 * file image. Clear the relocation 201 * record so that it will not be 202 * performed again. 203 */ 204 reloc->r_flags = 205 (FLG_R_APPLY | FLG_R_CLR); 206 reloc->r_value = addr; 207 if (IS_PC_RELATIVE(type)) 208 reloc->r_value -= offset; 209 210 if (unknown == 0) 211 unknown = 212 MSG_INTL(MSG_STR_UNKNOWN); 213 reloc->r_name = unknown; 214 (*null)++; 215 } else { 216 /* 217 * Any non-relative relocation should be 218 * left alone, but its offset should be 219 * updated to any new fixed address. 220 */ 221 reloc->r_flags = FLG_R_INC; 222 reloc->r_value = addr; 223 if (type == M_R_JMP_SLOT) 224 (*func)++; 225 else 226 (*data)++; 227 } 228 } 229 continue; 230 } 231 232 /* 233 * Analyze the case where more than just relative relocations 234 * are to be applied. 235 */ 236 if (bind == STB_LOCAL) { 237 if (flags & RTLD_MEMORY) { 238 /* 239 * Save the relative relocations from the memory 240 * image. The data itself has already been 241 * relocated, thus clear the relocation record 242 * so that it will not be performed again. 243 */ 244 reloc->r_flags = FLG_R_CLR; 245 } else { 246 /* 247 * Apply relative relocation to the file image. 248 * Clear the relocation record so that it will 249 * not be performed again. 250 */ 251 reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR); 252 reloc->r_value = addr; 253 if (IS_PC_RELATIVE(type)) 254 reloc->r_value -= offset; 255 256 if (unknown == 0) 257 unknown = MSG_INTL(MSG_STR_UNKNOWN); 258 reloc->r_name = unknown; 259 } 260 (*null)++; 261 continue; 262 } 263 264 /* 265 * At this point we're dealing with a non-relative relocation 266 * that requires the symbol definition. 267 */ 268 name = strs + sym->st_name; 269 270 /* 271 * Find the symbol. As the object being investigated is already 272 * a part of this process, the symbol lookup will likely 273 * succeed. However, because of lazy binding, there is still 274 * the possibility of a dangling .plt relocation. dldump() 275 * users might be encouraged to set LD_FLAGS=loadavail (crle(1) 276 * does this for them). 277 * 278 * Initialize the symbol lookup data structure. 279 */ 280 SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt, 281 0, rsymndx, sym, type, LKUP_STDRELOC); 282 283 _bound = _weak = 0; 284 _sym = sym; 285 if ((sym = lookup_sym(&sl, &_lmp, &binfo, NULL)) != 0) { 286 /* 287 * Determine from the various relocation requirements 288 * whether this binding is appropriate. If we're called 289 * from crle(1), RTLD_CONFSET is set, then only inspect 290 * objects selected from the configuration file 291 * (FL1_RT_CONFSET was set during load()). 292 */ 293 if (!(flags & RTLD_CONFSET) || 294 (FLAGS1(_lmp) & FL1_RT_CONFSET)) { 295 if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) || 296 ((flags & RTLD_REL_EXEC) && 297 (FLAGS(_lmp) & FLG_RT_ISMAIN)) || 298 ((flags & RTLD_REL_DEPENDS) && 299 (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) || 300 ((flags & RTLD_REL_PRELOAD) && 301 (FLAGS(_lmp) & FLG_RT_PRELOAD)) || 302 ((flags & RTLD_REL_SELF) && 303 (lmp == _lmp))) { 304 Aliste idx; 305 Word *ndx; 306 307 _bound = 1; 308 309 /* 310 * If this symbol is explicitly defined 311 * as nodirect, don't allow any local 312 * binding. 313 */ 314 for (ALIST_TRAVERSE(nodirect, idx, 315 ndx)) { 316 if (*ndx == rsymndx) { 317 _bound = 0; 318 break; 319 } 320 } 321 } 322 } 323 } else { 324 /* 325 * If this is a weak reference and we've been asked to 326 * bind unresolved weak references consider ourself 327 * bound. This category is typically set by clre(1) for 328 * an application cache. 329 */ 330 if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) && 331 (_sym->st_shndx == SHN_UNDEF) && 332 (flags & RTLD_REL_WEAK)) 333 _bound = _weak = 1; 334 } 335 336 if (flags & RTLD_MEMORY) { 337 if (_bound) { 338 /* 339 * We know that all data relocations will have 340 * been performed at process startup thus clear 341 * the relocation record so that it will not be 342 * performed again. However, we don't know what 343 * function relocations have been performed 344 * because of lazy binding - regardless, we can 345 * leave all the function relocation records in 346 * place, because if the function has already 347 * been bound the record won't be referenced 348 * anyway. In the case of using LD_BIND_NOW, 349 * a function may be bound twice - so what. 350 */ 351 if (type == M_R_JMP_SLOT) { 352 reloc->r_flags = FLG_R_INC; 353 (*func)++; 354 } else { 355 if (type != M_R_COPY) 356 reloc->r_flags = FLG_R_CLR; 357 (*null)++; 358 } 359 } else { 360 /* 361 * Clear any unrequired relocation. 362 */ 363 reloc->r_flags = FLG_R_UNDO | FLG_R_INC; 364 reloc->r_value = addr; 365 if (type == M_R_JMP_SLOT) 366 (*func)++; 367 else 368 (*data)++; 369 } 370 } else { 371 if (_bound) { 372 /* 373 * Apply the global relocation to the file 374 * image. Clear the relocation record so that 375 * it will not be performed again. 376 */ 377 if (_weak) { 378 reloc->r_value = 0; 379 reloc->r_size = 0; 380 } else { 381 reloc->r_value = sym->st_value; 382 if (IS_PC_RELATIVE(type)) 383 reloc->r_value -= offset; 384 if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) && 385 (sym->st_shndx != SHN_ABS)) 386 reloc->r_value += ADDR(_lmp); 387 reloc->r_size = sym->st_size; 388 } 389 390 reloc->r_flags = FLG_R_APPLY | FLG_R_CLR; 391 reloc->r_name = name; 392 if (type == M_R_JMP_SLOT) 393 (*func)++; 394 else 395 (*null)++; 396 } else { 397 /* 398 * Do not apply any unrequired relocations. 399 */ 400 reloc->r_flags = FLG_R_INC; 401 reloc->r_value = addr; 402 if (type == M_R_JMP_SLOT) 403 (*func)++; 404 else 405 (*data)++; 406 } 407 } 408 } 409 return (0); 410 } 411 412 413 /* 414 * Perform any relocation updates to the new image using the information from 415 * the `Reloc' structure constructed during count_reloc(). 416 */ 417 void 418 update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name, 419 Rt_map *lmp, Rel **null, Rel **data, Rel **func) 420 { 421 Shdr *shdr; 422 Rel *rel; 423 Reloc *reloc; 424 Xword ent, cnt, _cnt; 425 Cache *orcache, *ircache = 0; 426 Half ndx; 427 428 /* 429 * Set up to read the output relocation table. 430 */ 431 shdr = _icache->c_shdr; 432 rel = (Rel *)_icache->c_data->d_buf; 433 reloc = (Reloc *)_icache->c_info; 434 ent = shdr->sh_entsize; 435 cnt = shdr->sh_size / ent; 436 437 /* 438 * Loop through the relocation table. 439 */ 440 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++, 441 rel = (Rel *)((uintptr_t)rel + ent)) { 442 uchar_t *iaddr, *oaddr; 443 /* LINTED */ 444 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH); 445 Addr off, bgn, end; 446 447 /* 448 * Ignore null relocations (these may have been created from a 449 * previous dldump() of this image). 450 */ 451 if (type == M_R_NONE) { 452 (*null)++; 453 continue; 454 } 455 456 /* 457 * Determine the section being relocated if we haven't already 458 * done so (we may have had to skip over some null relocation to 459 * get to the first valid offset). The System V ABI states that 460 * a relocation sections sh_info field indicates the section 461 * that must be relocated. However, on Intel it seems that the 462 * .rel.plt sh_info records the section index of the .plt, when 463 * in fact it's the .got that gets relocated. In addition we 464 * now create combined relocation sections with -zcomreloc. To 465 * generically be able to cope with these anomalies, search for 466 * the appropriate section to be relocated by comparing the 467 * offset of the first relocation record against each sections 468 * offset and size. 469 */ 470 /* BEGIN CSTYLED */ 471 #if !defined(__lint) 472 if ((ircache == (Cache *)0) || (rel->r_offset < bgn) || 473 (rel->r_offset > end)) { 474 #else 475 /* 476 * lint sees `bgn' and `end' as potentially referenced 477 * before being set. 478 */ 479 if (ircache == (Cache *)0) { 480 #endif 481 _icache = icache; 482 _icache++; 483 484 for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++, 485 _icache++) { 486 487 shdr = _icache->c_shdr; 488 bgn = shdr->sh_addr; 489 end = bgn + shdr->sh_size; 490 491 if ((rel->r_offset >= bgn) && 492 (rel->r_offset <= end)) 493 break; 494 } 495 ircache = &icache[ndx]; 496 orcache = &ocache[ndx]; 497 } 498 /* END CSTYLED */ 499 500 /* 501 * Determine the relocation location of both the input and 502 * output data. Take into account that an input section may be 503 * NOBITS (ppc .plt for example). 504 */ 505 off = rel->r_offset - ircache->c_shdr->sh_addr; 506 if (ircache->c_data->d_buf) 507 iaddr = (uchar_t *)ircache->c_data->d_buf + off; 508 else 509 iaddr = 0; 510 oaddr = (uchar_t *)orcache->c_data->d_buf + off; 511 512 /* 513 * Apply the relocation to the new output image. Any base 514 * address, or symbol value, will have been saved in the reloc 515 * structure during count_reloc(). 516 */ 517 if (reloc->r_flags & FLG_R_APPLY) 518 apply_reloc(rel, reloc, name, oaddr, lmp); 519 520 /* 521 * Undo any relocation that might already been applied to the 522 * memory image by the runtime linker. Using the original 523 * file, determine the relocation offset original value and 524 * restore the new image to that value. 525 */ 526 if ((reloc->r_flags & FLG_R_UNDO) && 527 (FLAGS(lmp) & FLG_RT_RELOCED)) 528 undo_reloc(rel, oaddr, iaddr, reloc); 529 530 /* 531 * If a relocation has been applied then the relocation record 532 * should be cleared so that the relocation isn't applied again 533 * when the new image is used. 534 */ 535 if (reloc->r_flags & FLG_R_CLR) { 536 if (type == M_R_JMP_SLOT) { 537 clear_reloc(*func); 538 *func = (Rel *)((uintptr_t)*func + ent); 539 } else { 540 clear_reloc(*null); 541 *null = (Rel *)((uintptr_t)*null + ent); 542 } 543 } 544 545 /* 546 * If a relocation isn't applied, update the relocation record 547 * to take into account the new address of the image. 548 */ 549 if (reloc->r_flags & FLG_R_INC) { 550 if (type == M_R_JMP_SLOT) { 551 inc_reloc(*func, rel, reloc, oaddr, iaddr); 552 *func = (Rel *)((uintptr_t)*func + ent); 553 } else { 554 inc_reloc(*data, rel, reloc, oaddr, iaddr); 555 *data = (Rel *)((uintptr_t)*data + ent); 556 } 557 } 558 } 559 } 560