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 (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 24 * 25 * Update any dynamic entry offsets. One issue with dynamic entries is that 26 * you only know whether they refer to a value or an offset if you know each 27 * type. Thus we check for all types we know about, it a type is found that 28 * we don't know about then return and error as we have no idea what to do. 29 */ 30 31 #include <libelf.h> 32 #include <link.h> 33 #include "libld.h" 34 #include "msg.h" 35 #include "rtld.h" 36 #include "_librtld.h" 37 38 int 39 update_dynamic(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, 40 Addr addr, Off off, const char *file, Xword null, Xword data, Xword func, 41 Xword entsize, Xword checksum) 42 { 43 Dyn *dyn = (Dyn *)_cache->c_data->d_buf, *posdyn = 0; 44 const char *strs; 45 Cache *__cache; 46 47 /* 48 * If we're dealing with an object that might have bound to an external 49 * dependency establish our string table for possible NEEDED processing. 50 */ 51 if (flags & RTLD_REL_DEPENDS) { 52 __cache = &cache[_cache->c_shdr->sh_link]; 53 strs = (const char *)__cache->c_data->d_buf; 54 } 55 56 /* 57 * Loop through the dynamic table updating all offsets. 58 */ 59 while (dyn->d_tag != DT_NULL) { 60 Rt_map *dlmp; 61 62 switch ((Xword)dyn->d_tag) { 63 case DT_NEEDED: 64 if (posdyn == 0) 65 break; 66 67 /* 68 * Determine whether this dependency has been loaded 69 * (this is the most generic way to check any alias 70 * names), and if it has been bound to, undo any 71 * lazy-loading or deferred position flag. 72 */ 73 if (dlmp = is_so_loaded(LIST(lmp), 74 (strs + dyn->d_un.d_val), NULL)) { 75 Bnd_desc *bdp; 76 Aliste idx; 77 78 for (APLIST_TRAVERSE(DEPENDS(lmp), idx, bdp)) { 79 if (dlmp != bdp->b_depend) 80 continue; 81 82 posdyn->d_un.d_val &= 83 ~(DF_P1_LAZYLOAD | DF_P1_DEFERRED); 84 break; 85 } 86 } 87 break; 88 89 case DT_RELAENT: 90 case DT_STRSZ: 91 case DT_SYMENT: 92 case DT_SONAME: 93 case DT_RPATH: 94 case DT_SYMBOLIC: 95 case DT_RELENT: 96 case DT_PLTREL: 97 case DT_TEXTREL: 98 case DT_VERDEFNUM: 99 case DT_VERNEEDNUM: 100 case DT_AUXILIARY: 101 case DT_USED: 102 case DT_FILTER: 103 case DT_DEPRECATED_SPARC_REGISTER: 104 case M_DT_REGISTER: 105 case DT_BIND_NOW: 106 case DT_INIT_ARRAYSZ: 107 case DT_FINI_ARRAYSZ: 108 case DT_RUNPATH: 109 case DT_FLAGS: 110 case DT_CONFIG: 111 case DT_DEPAUDIT: 112 case DT_AUDIT: 113 case DT_SUNW_SYMSZ: 114 break; 115 case DT_PLTGOT: 116 case DT_HASH: 117 case DT_STRTAB: 118 case DT_SYMTAB: 119 case DT_SUNW_SYMTAB: 120 case DT_INIT: 121 case DT_FINI: 122 case DT_VERSYM: 123 case DT_VERDEF: 124 case DT_VERNEED: 125 case DT_INIT_ARRAY: 126 case DT_FINI_ARRAY: 127 dyn->d_un.d_ptr += addr; 128 break; 129 130 /* 131 * If the memory image is being used, this element would have 132 * been initialized to the runtime linkers internal link-map 133 * list. Clear it. 134 */ 135 case DT_DEBUG: 136 dyn->d_un.d_val = 0; 137 break; 138 139 /* 140 * The number of relocations may have been reduced if 141 * relocations have been saved in the new image. Thus we 142 * compute the new relocation size and start. 143 */ 144 case DT_RELASZ: 145 case DT_RELSZ: 146 dyn->d_un.d_val = ((data + func) * entsize); 147 break; 148 149 case DT_RELA: 150 case DT_REL: 151 dyn->d_un.d_ptr = (addr + off + (null * entsize)); 152 break; 153 154 /* 155 * If relative relocations have been processed clear the count. 156 */ 157 case DT_RELACOUNT: 158 case DT_RELCOUNT: 159 if (flags & RTLD_REL_RELATIVE) 160 dyn->d_un.d_val = 0; 161 break; 162 163 case DT_PLTRELSZ: 164 dyn->d_un.d_val = (func * entsize); 165 break; 166 167 case DT_JMPREL: 168 dyn->d_un.d_ptr = (addr + off + 169 ((null + data) * entsize)); 170 break; 171 172 /* 173 * Recompute the images elf checksum. 174 */ 175 case DT_CHECKSUM: 176 dyn->d_un.d_val = checksum; 177 break; 178 179 /* 180 * If a flag entry is available, indicate if this image has 181 * been generated via the configuration process (crle(1)). 182 * Because we only started depositing DT_FLAGS_1 entries in all 183 * objects starting with Solaris 8, set a feature flag if it 184 * is present (these got added in Solaris 7). 185 * The runtime linker may use this flag to search for a local 186 * configuration file - this is only meaningful in executables 187 * but the flag has value for identifying images regardless. 188 * 189 * If this file is acting as a filter, and dependency 190 * relocations have been processed (a filter is thought of as a 191 * dependency in terms of symbol binding), we may have bound to 192 * the filtee, and hence carried out the relocation. Indicate 193 * that the filtee must be preloaded, as the .plt won't get 194 * exercised to cause its normal loading. 195 */ 196 case DT_FLAGS_1: 197 if (flags & RTLD_CONFSET) 198 dyn->d_un.d_val |= DF_1_CONFALT; 199 if ((flags & RTLD_REL_DEPENDS) && 200 (FLAGS1(lmp)) & MSK_RT_FILTER) 201 dyn->d_un.d_val |= DF_1_LOADFLTR; 202 break; 203 204 case DT_FEATURE_1: 205 if (flags & RTLD_CONFSET) 206 dyn->d_un.d_val |= DTF_1_CONFEXP; 207 break; 208 209 /* 210 * If a position flag is available save it for possible update 211 * when processing the next NEEDED tag. 212 */ 213 case DT_POSFLAG_1: 214 if (flags & RTLD_REL_DEPENDS) { 215 posdyn = dyn++; 216 continue; 217 } 218 break; 219 220 /* 221 * Collect the defaults. 222 */ 223 default: 224 /* 225 * If d_val is used, don't touch. 226 */ 227 if ((dyn->d_tag >= DT_VALRNGLO) && 228 (dyn->d_tag <= DT_VALRNGHI)) 229 break; 230 231 /* 232 * If d_ptr is used, adjust. Note, some entries that 233 * fell into this range are offsets into the dynamic 234 * string table. Although these would need modifying 235 * if the section itself were resized, there is no 236 * resizing with dldump(). Entries that correspond to 237 * offsets are picked off in the initial DT_ loop 238 * above. 239 */ 240 if ((dyn->d_tag >= DT_ADDRRNGLO) && 241 (dyn->d_tag <= DT_ADDRRNGHI)) { 242 dyn->d_un.d_ptr += addr; 243 break; 244 } 245 246 /* 247 * Check to see if this DT_ entry conforms 248 * to the DT_ENCODING rules. 249 */ 250 if ((dyn->d_tag >= DT_ENCODING) && 251 (dyn->d_tag <= DT_HIOS)) { 252 /* 253 * Even tag values are ADDRESS encodings 254 */ 255 if ((dyn->d_tag % 2) == 0) { 256 dyn->d_un.d_ptr += addr; 257 } 258 break; 259 } 260 eprintf(LIST(lmp), ERR_WARNING, 261 MSG_INTL(MSG_DT_UNKNOWN), file, 262 EC_XWORD(dyn->d_tag)); 263 return (1); 264 } 265 posdyn = 0; 266 dyn++; 267 } 268 return (0); 269 } 270