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 #include <libelf.h> 28 #include <dlfcn.h> 29 #include "machdep.h" 30 #include "reloc.h" 31 #include "msg.h" 32 #include "_librtld.h" 33 #include "alist.h" 34 35 static const char *unknown = 0; /* Stash MSG_INTL(MSG_STR_UNKNOWN) */ 36 37 /* 38 * Process all relocation records. A new `Reloc' structure is allocated to 39 * cache the processing decisions deduced, and these will be applied during 40 * update_reloc(). 41 * A count of the number of null relocations (i.e., relocations that will be 42 * fixed and whoes records will be nulled out), data and function relocations 43 * is maintained. This allows the relocation records themselves to be 44 * rearranged (localized) later if necessary. Note that the number of function 45 * relocations, although coounted, shouldn't differ from the original file, 46 * the index of a .plt must be maintained to the index of its relocation record 47 * within the associated relocation section. 48 * 49 * The intention behind this file is to maintain as much relocation logic as 50 * possible in a generic form. 51 */ 52 int 53 count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr, 54 Xword *null, Xword *data, Xword *func, Alist *nodirect) 55 { 56 Rel *rel; 57 Reloc *reloc; 58 Shdr *shdr; 59 Xword ent, cnt, _cnt; 60 Sym *syms; 61 const char *strs; 62 Cache *__cache; 63 Xword pltndx = 0; 64 65 /* 66 * Determine the number of relocation entries we'll be dealing with. 67 */ 68 shdr = _cache->c_shdr; 69 rel = (Rel *)_cache->c_data->d_buf; 70 ent = shdr->sh_entsize; 71 cnt = shdr->sh_size / ent; 72 73 /* 74 * Allocate a relocation structure for this relocation section. 75 */ 76 if ((reloc = calloc(cnt, sizeof (Reloc))) == 0) 77 return (1); 78 _cache->c_info = (void *)reloc; 79 80 /* 81 * Determine the relocations associated symbol and string table. 82 */ 83 __cache = &cache[shdr->sh_link]; 84 syms = (Sym *)__cache->c_data->d_buf; 85 shdr = __cache->c_shdr; 86 __cache = &cache[shdr->sh_link]; 87 strs = (const char *)__cache->c_data->d_buf; 88 89 /* 90 * Loop through the relocation table. 91 */ 92 for (_cnt = 0; _cnt < cnt; _cnt++, reloc++, 93 rel = (Rel *)((uintptr_t)rel + ent)) { 94 const char *name; 95 /* LINTED */ 96 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH); 97 uchar_t bind; 98 ulong_t offset = rel->r_offset + addr; 99 Rt_map *_lmp; 100 int _bound, _weak; 101 ulong_t rsymndx = ELF_R_SYM(rel->r_info); 102 Slookup sl; 103 Sresult sr; 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, and symbol result, data 279 * structures. 280 */ 281 SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt, 282 0, rsymndx, sym, type, LKUP_STDRELOC); 283 SRESULT_INIT(sr, name); 284 285 _bound = _weak = 0; 286 _sym = sym; 287 if (lookup_sym(&sl, &sr, &binfo, NULL)) { 288 _lmp = sr.sr_dmap; 289 sym = sr.sr_sym; 290 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 idx; 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, idx, 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, M_MACH); 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 /* BEGIN CSTYLED */ 476 #if !defined(__lint) 477 if ((ircache == (Cache *)0) || (rel->r_offset < bgn) || 478 (rel->r_offset > end)) { 479 #else 480 /* 481 * lint sees `bgn' and `end' as potentially referenced 482 * before being set. 483 */ 484 if (ircache == (Cache *)0) { 485 #endif 486 _icache = icache; 487 _icache++; 488 489 for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++, 490 _icache++) { 491 492 shdr = _icache->c_shdr; 493 bgn = shdr->sh_addr; 494 end = bgn + shdr->sh_size; 495 496 if ((rel->r_offset >= bgn) && 497 (rel->r_offset <= end)) 498 break; 499 } 500 ircache = &icache[ndx]; 501 orcache = &ocache[ndx]; 502 } 503 /* END CSTYLED */ 504 505 /* 506 * Determine the relocation location of both the input and 507 * output data. Take into account that an input section may be 508 * NOBITS (ppc .plt for example). 509 */ 510 off = rel->r_offset - ircache->c_shdr->sh_addr; 511 if (ircache->c_data->d_buf) 512 iaddr = (uchar_t *)ircache->c_data->d_buf + off; 513 else 514 iaddr = 0; 515 oaddr = (uchar_t *)orcache->c_data->d_buf + off; 516 517 /* 518 * Apply the relocation to the new output image. Any base 519 * address, or symbol value, will have been saved in the reloc 520 * structure during count_reloc(). 521 */ 522 if (reloc->r_flags & FLG_R_APPLY) 523 apply_reloc(rel, reloc, name, oaddr, lmp); 524 525 /* 526 * Undo any relocation that might already been applied to the 527 * memory image by the runtime linker. Using the original 528 * file, determine the relocation offset original value and 529 * restore the new image to that value. 530 */ 531 if ((reloc->r_flags & FLG_R_UNDO) && 532 (FLAGS(lmp) & FLG_RT_RELOCED)) 533 undo_reloc(rel, oaddr, iaddr, reloc); 534 535 /* 536 * If a relocation has been applied then the relocation record 537 * should be cleared so that the relocation isn't applied again 538 * when the new image is used. 539 */ 540 if (reloc->r_flags & FLG_R_CLR) { 541 if (type == M_R_JMP_SLOT) { 542 clear_reloc(*func); 543 *func = (Rel *)((uintptr_t)*func + ent); 544 } else { 545 clear_reloc(*null); 546 *null = (Rel *)((uintptr_t)*null + ent); 547 } 548 } 549 550 /* 551 * If a relocation isn't applied, update the relocation record 552 * to take into account the new address of the image. 553 */ 554 if (reloc->r_flags & FLG_R_INC) { 555 if (type == M_R_JMP_SLOT) { 556 inc_reloc(*func, rel, reloc, oaddr, iaddr); 557 *func = (Rel *)((uintptr_t)*func + ent); 558 } else { 559 inc_reloc(*data, rel, reloc, oaddr, iaddr); 560 *data = (Rel *)((uintptr_t)*data + ent); 561 } 562 } 563 } 564 } 565