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); 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 sl.sl_name = name; 279 sl.sl_cmap = lmp; 280 sl.sl_imap = LIST(lmp)->lm_head; 281 sl.sl_hash = 0; 282 sl.sl_rsymndx = rsymndx; 283 sl.sl_rsym = sym; 284 285 if (type == M_R_COPY) 286 sl.sl_flags = LKUP_COPY; 287 else 288 sl.sl_flags = LKUP_DEFT; 289 290 _bound = _weak = 0; 291 _sym = sym; 292 if ((sym = lookup_sym(&sl, &_lmp, &binfo)) != 0) { 293 /* 294 * Determine from the various relocation requirements 295 * whether this binding is appropriate. If we're called 296 * from crle(1), RTLD_CONFSET is set, then only inspect 297 * objects selected from the configuration file 298 * (FL1_RT_CONFSET was set during load()). 299 */ 300 if (!(flags & RTLD_CONFSET) || 301 (FLAGS1(_lmp) & FL1_RT_CONFSET)) { 302 if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) || 303 ((flags & RTLD_REL_EXEC) && 304 (FLAGS(_lmp) & FLG_RT_ISMAIN)) || 305 ((flags & RTLD_REL_DEPENDS) && 306 (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) || 307 ((flags & RTLD_REL_PRELOAD) && 308 (FLAGS(_lmp) & FLG_RT_PRELOAD)) || 309 ((flags & RTLD_REL_SELF) && 310 (lmp == _lmp))) { 311 Aliste idx; 312 Word *ndx; 313 314 _bound = 1; 315 316 /* 317 * If this symbol is explicitly defined 318 * as nodirect, don't allow any local 319 * binding. 320 */ 321 for (ALIST_TRAVERSE(nodirect, idx, 322 ndx)) { 323 if (*ndx == rsymndx) { 324 _bound = 0; 325 break; 326 } 327 } 328 } 329 } 330 } else { 331 /* 332 * If this is a weak reference and we've been asked to 333 * bind unresolved weak references consider ourself 334 * bound. This category is typically set by clre(1) for 335 * an application cache. 336 */ 337 if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) && 338 (_sym->st_shndx == SHN_UNDEF) && 339 (flags & RTLD_REL_WEAK)) 340 _bound = _weak = 1; 341 } 342 343 if (flags & RTLD_MEMORY) { 344 if (_bound) { 345 /* 346 * We know that all data relocations will have 347 * been performed at process startup thus clear 348 * the relocation record so that it will not be 349 * performed again. However, we don't know what 350 * function relocations have been performed 351 * because of lazy binding - regardless, we can 352 * leave all the function relocation records in 353 * place, because if the function has already 354 * been bound the record won't be referenced 355 * anyway. In the case of using LD_BIND_NOW, 356 * a function may be bound twice - so what. 357 */ 358 if (type == M_R_JMP_SLOT) { 359 reloc->r_flags = FLG_R_INC; 360 (*func)++; 361 } else { 362 if (type != M_R_COPY) 363 reloc->r_flags = FLG_R_CLR; 364 (*null)++; 365 } 366 } else { 367 /* 368 * Clear any unrequired relocation. 369 */ 370 reloc->r_flags = FLG_R_UNDO | FLG_R_INC; 371 reloc->r_value = addr; 372 if (type == M_R_JMP_SLOT) 373 (*func)++; 374 else 375 (*data)++; 376 } 377 } else { 378 if (_bound) { 379 /* 380 * Apply the global relocation to the file 381 * image. Clear the relocation record so that 382 * it will not be performed again. 383 */ 384 if (_weak) { 385 reloc->r_value = 0; 386 reloc->r_size = 0; 387 } else { 388 reloc->r_value = sym->st_value; 389 if (IS_PC_RELATIVE(type)) 390 reloc->r_value -= offset; 391 if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) && 392 (sym->st_shndx != SHN_ABS)) 393 reloc->r_value += ADDR(_lmp); 394 reloc->r_size = sym->st_size; 395 } 396 397 reloc->r_flags = FLG_R_APPLY | FLG_R_CLR; 398 reloc->r_name = name; 399 if (type == M_R_JMP_SLOT) 400 (*func)++; 401 else 402 (*null)++; 403 } else { 404 /* 405 * Do not apply any unrequired relocations. 406 */ 407 reloc->r_flags = FLG_R_INC; 408 reloc->r_value = addr; 409 if (type == M_R_JMP_SLOT) 410 (*func)++; 411 else 412 (*data)++; 413 } 414 } 415 } 416 return (0); 417 } 418 419 420 /* 421 * Perform any relocation updates to the new image using the information from 422 * the `Reloc' structure constructed during count_reloc(). 423 */ 424 void 425 update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name, 426 Rt_map *lmp, Rel **null, Rel **data, Rel **func) 427 { 428 Shdr *shdr; 429 Rel *rel; 430 Reloc *reloc; 431 Xword ent, cnt, _cnt; 432 Cache *orcache, *ircache = 0; 433 Half ndx; 434 435 /* 436 * Set up to read the output relocation table. 437 */ 438 shdr = _icache->c_shdr; 439 rel = (Rel *)_icache->c_data->d_buf; 440 reloc = (Reloc *)_icache->c_info; 441 ent = shdr->sh_entsize; 442 cnt = shdr->sh_size / ent; 443 444 /* 445 * Loop through the relocation table. 446 */ 447 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++, 448 rel = (Rel *)((uintptr_t)rel + ent)) { 449 uchar_t *iaddr, *oaddr; 450 /* LINTED */ 451 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info); 452 Addr off, bgn, end; 453 454 /* 455 * Ignore null relocations (these may have been created from a 456 * previous dldump() of this image). 457 */ 458 if (type == M_R_NONE) { 459 (*null)++; 460 continue; 461 } 462 463 /* 464 * Determine the section being relocated if we haven't already 465 * done so (we may have had to skip over some null relocation to 466 * get to the first valid offset). The System V ABI states that 467 * a relocation sections sh_info field indicates the section 468 * that must be relocated. However, on Intel it seems that the 469 * .rel.plt sh_info records the section index of the .plt, when 470 * in fact it's the .got that gets relocated. In addition we 471 * now create combined relocation sections with -zcomreloc. To 472 * generically be able to cope with these anomalies, search for 473 * the appropriate section to be relocated by comparing the 474 * offset of the first relocation record against each sections 475 * offset and size. 476 */ 477 /* BEGIN CSTYLED */ 478 #if !defined(__lint) 479 if ((ircache == (Cache *)0) || (rel->r_offset < bgn) || 480 (rel->r_offset > end)) { 481 #else 482 /* 483 * lint sees `bgn' and `end' as potentially referenced 484 * before being set. 485 */ 486 if (ircache == (Cache *)0) { 487 #endif 488 _icache = icache; 489 _icache++; 490 491 for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++, 492 _icache++) { 493 494 shdr = _icache->c_shdr; 495 bgn = shdr->sh_addr; 496 end = bgn + shdr->sh_size; 497 498 if ((rel->r_offset >= bgn) && 499 (rel->r_offset <= end)) 500 break; 501 } 502 ircache = &icache[ndx]; 503 orcache = &ocache[ndx]; 504 } 505 /* END CSTYLED */ 506 507 /* 508 * Determine the relocation location of both the input and 509 * output data. Take into account that an input section may be 510 * NOBITS (ppc .plt for example). 511 */ 512 off = rel->r_offset - ircache->c_shdr->sh_addr; 513 if (ircache->c_data->d_buf) 514 iaddr = (uchar_t *)ircache->c_data->d_buf + off; 515 else 516 iaddr = 0; 517 oaddr = (uchar_t *)orcache->c_data->d_buf + off; 518 519 /* 520 * Apply the relocation to the new output image. Any base 521 * address, or symbol value, will have been saved in the reloc 522 * structure during count_reloc(). 523 */ 524 if (reloc->r_flags & FLG_R_APPLY) 525 apply_reloc(rel, reloc, name, oaddr, lmp); 526 527 /* 528 * Undo any relocation that might already been applied to the 529 * memory image by the runtime linker. Using the original 530 * file, determine the relocation offset original value and 531 * restore the new image to that value. 532 */ 533 if ((reloc->r_flags & FLG_R_UNDO) && 534 (FLAGS(lmp) & FLG_RT_RELOCED)) 535 undo_reloc(rel, oaddr, iaddr, reloc); 536 537 /* 538 * If a relocation has been applied then the relocation record 539 * should be cleared so that the relocation isn't applied again 540 * when the new image is used. 541 */ 542 if (reloc->r_flags & FLG_R_CLR) { 543 if (type == M_R_JMP_SLOT) { 544 clear_reloc(*func); 545 *func = (Rel *)((uintptr_t)*func + ent); 546 } else { 547 clear_reloc(*null); 548 *null = (Rel *)((uintptr_t)*null + ent); 549 } 550 } 551 552 /* 553 * If a relocation isn't applied, update the relocation record 554 * to take into account the new address of the image. 555 */ 556 if (reloc->r_flags & FLG_R_INC) { 557 if (type == M_R_JMP_SLOT) { 558 inc_reloc(*func, rel, reloc, oaddr, iaddr); 559 *func = (Rel *)((uintptr_t)*func + ent); 560 } else { 561 inc_reloc(*data, rel, reloc, oaddr, iaddr); 562 *data = (Rel *)((uintptr_t)*data + ent); 563 } 564 } 565 } 566 } 567