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