/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * * Update any dynamic entry offsets. One issue with dynamic entries is that * you only know whether they refer to a value or an offset if you know each * type. Thus we check for all types we know about, it a type is found that * we don't know about then return and error as we have no idea what to do. */ #include #include #include "libld.h" #include "msg.h" #include "rtld.h" #include "_librtld.h" int update_dynamic(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr, Off off, const char *file, Xword null, Xword data, Xword func, Xword entsize, Xword checksum) { Dyn *dyn = (Dyn *)_cache->c_data->d_buf, *posdyn = 0; const char *strs; Cache *__cache; /* * If we're dealing with an object that might have bound to an external * dependency establish our string table for possible NEEDED processing. */ if (flags & RTLD_REL_DEPENDS) { __cache = &cache[_cache->c_shdr->sh_link]; strs = (const char *)__cache->c_data->d_buf; } /* * Loop through the dynamic table updating all offsets. */ while (dyn->d_tag != DT_NULL) { Rt_map *dlmp; switch ((Xword)dyn->d_tag) { case DT_NEEDED: if (posdyn == 0) break; /* * Determine whether this dependency has been loaded * (this is the most generic way to check any alias * names), and if it has been bound to, undo any * lazy-loading or deferred position flag. */ if (dlmp = is_so_loaded(LIST(lmp), (strs + dyn->d_un.d_val), NULL)) { Bnd_desc *bdp; Aliste idx; for (APLIST_TRAVERSE(DEPENDS(lmp), idx, bdp)) { if (dlmp != bdp->b_depend) continue; posdyn->d_un.d_val &= ~(DF_P1_LAZYLOAD | DF_P1_DEFERRED); break; } } break; case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_SYMBOLIC: case DT_RELENT: case DT_PLTREL: case DT_TEXTREL: case DT_VERDEFNUM: case DT_VERNEEDNUM: case DT_AUXILIARY: case DT_USED: case DT_FILTER: case DT_DEPRECATED_SPARC_REGISTER: case M_DT_REGISTER: case DT_BIND_NOW: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_RUNPATH: case DT_FLAGS: case DT_CONFIG: case DT_DEPAUDIT: case DT_AUDIT: case DT_SUNW_SYMSZ: break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_SUNW_SYMTAB: case DT_INIT: case DT_FINI: case DT_VERSYM: case DT_VERDEF: case DT_VERNEED: case DT_INIT_ARRAY: case DT_FINI_ARRAY: dyn->d_un.d_ptr += addr; break; /* * If the memory image is being used, this element would have * been initialized to the runtime linkers internal link-map * list. Clear it. */ case DT_DEBUG: dyn->d_un.d_val = 0; break; /* * The number of relocations may have been reduced if * relocations have been saved in the new image. Thus we * compute the new relocation size and start. */ case DT_RELASZ: case DT_RELSZ: dyn->d_un.d_val = ((data + func) * entsize); break; case DT_RELA: case DT_REL: dyn->d_un.d_ptr = (addr + off + (null * entsize)); break; /* * If relative relocations have been processed clear the count. */ case DT_RELACOUNT: case DT_RELCOUNT: if (flags & RTLD_REL_RELATIVE) dyn->d_un.d_val = 0; break; case DT_PLTRELSZ: dyn->d_un.d_val = (func * entsize); break; case DT_JMPREL: dyn->d_un.d_ptr = (addr + off + ((null + data) * entsize)); break; /* * Recompute the images elf checksum. */ case DT_CHECKSUM: dyn->d_un.d_val = checksum; break; /* * If a flag entry is available, indicate if this image has * been generated via the configuration process (crle(1)). * Because we only started depositing DT_FLAGS_1 entries in all * objects starting with Solaris 8, set a feature flag if it * is present (these got added in Solaris 7). * The runtime linker may use this flag to search for a local * configuration file - this is only meaningful in executables * but the flag has value for identifying images regardless. * * If this file is acting as a filter, and dependency * relocations have been processed (a filter is thought of as a * dependency in terms of symbol binding), we may have bound to * the filtee, and hence carried out the relocation. Indicate * that the filtee must be preloaded, as the .plt won't get * exercised to cause its normal loading. */ case DT_FLAGS_1: if (flags & RTLD_CONFSET) dyn->d_un.d_val |= DF_1_CONFALT; if ((flags & RTLD_REL_DEPENDS) && (FLAGS1(lmp)) & MSK_RT_FILTER) dyn->d_un.d_val |= DF_1_LOADFLTR; break; case DT_FEATURE_1: if (flags & RTLD_CONFSET) dyn->d_un.d_val |= DTF_1_CONFEXP; break; /* * If a position flag is available save it for possible update * when processing the next NEEDED tag. */ case DT_POSFLAG_1: if (flags & RTLD_REL_DEPENDS) { posdyn = dyn++; continue; } break; /* * Collect the defaults. */ default: /* * If d_val is used, don't touch. */ if ((dyn->d_tag >= DT_VALRNGLO) && (dyn->d_tag <= DT_VALRNGHI)) break; /* * If d_ptr is used, adjust. Note, some entries that * fell into this range are offsets into the dynamic * string table. Although these would need modifying * if the section itself were resized, there is no * resizing with dldump(). Entries that correspond to * offsets are picked off in the initial DT_ loop * above. */ if ((dyn->d_tag >= DT_ADDRRNGLO) && (dyn->d_tag <= DT_ADDRRNGHI)) { dyn->d_un.d_ptr += addr; break; } /* * Check to see if this DT_ entry conforms * to the DT_ENCODING rules. */ if ((dyn->d_tag >= DT_ENCODING) && (dyn->d_tag <= DT_HIOS)) { /* * Even tag values are ADDRESS encodings */ if ((dyn->d_tag % 2) == 0) { dyn->d_un.d_ptr += addr; } break; } eprintf(LIST(lmp), ERR_WARNING, MSG_INTL(MSG_DT_UNKNOWN), file, EC_XWORD(dyn->d_tag)); return (1); } posdyn = 0; dyn++; } return (0); }