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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <string.h> 28 #include <debug.h> 29 #include "msg.h" 30 #include "_libld.h" 31 32 /* 33 * Scan all partially initialized symbols to determine what output Move sections 34 * or partially expanded data section, must be created. 35 */ 36 static uintptr_t 37 make_mvsections(Ofl_desc *ofl) 38 { 39 Aliste idx; 40 Sym_desc *sdp; 41 Word mv_nums = 0; 42 Xword align_parexpn = 0; /* for -z nopartial .data sec */ 43 size_t size_parexpn = 0; /* size of parexpn section */ 44 45 /* 46 * Compute the size of the output move section 47 */ 48 for (APLIST_TRAVERSE(ofl->ofl_parsyms, idx, sdp)) { 49 if (sdp->sd_flags & FLG_SY_PAREXPN) { 50 Sym *sym = sdp->sd_sym; 51 Xword align_val; 52 53 if (sym->st_shndx == SHN_COMMON) 54 align_val = sym->st_value; 55 else 56 align_val = 8; 57 58 /* 59 * This global symbol is redirected to the special 60 * partial initialization .data section. 61 */ 62 size_parexpn = (size_t)S_ROUND(size_parexpn, 63 sym->st_value) + sym->st_size; 64 if (align_val > align_parexpn) 65 align_parexpn = align_val; 66 67 } else { 68 mv_nums += alist_nitems(sdp->sd_move); 69 } 70 } 71 72 /* 73 * Generate a new Move section. 74 */ 75 if (mv_nums && (ld_make_sunwmove(ofl, mv_nums) == S_ERROR)) 76 return (S_ERROR); 77 78 /* 79 * Add empty area for partially initialized symbols. 80 * 81 * A special .data section is created when the '-z nopartial' 82 * option is in effect in order to receive the expanded data. 83 */ 84 if (size_parexpn) { 85 /* LINTED */ 86 if (ld_make_parexpn_data(ofl, size_parexpn, 87 align_parexpn) == S_ERROR) 88 return (S_ERROR); 89 } 90 return (1); 91 } 92 93 /* 94 * Assign move descriptors with the associated target symbol. 95 */ 96 static uintptr_t 97 append_move_desc(Ofl_desc *ofl, Sym_desc *sdp, Move *mvp, Is_desc *isp) 98 { 99 int i, cnt = mvp->m_repeat; 100 101 for (i = 0; i < cnt; i++) { 102 Aliste idx; 103 Mv_desc *omdp, nmd; 104 105 /* LINTED */ 106 nmd.md_len = ELF_M_SIZE(mvp->m_info); 107 nmd.md_start = mvp->m_poffset + i * 108 ((mvp->m_stride + 1) * nmd.md_len); 109 nmd.md_move = mvp; 110 111 /* 112 * Verify that this move descriptor doesn't overlap any existing 113 * move descriptors. 114 */ 115 for (ALIST_TRAVERSE(sdp->sd_move, idx, omdp)) { 116 Mv_desc *smdp, *lmdp; 117 118 if (nmd.md_start > omdp->md_start) { 119 smdp = omdp; 120 lmdp = &nmd; 121 } else { 122 smdp = &nmd; 123 lmdp = omdp; 124 } 125 126 /* 127 * If this move entry is exactly the same as that of 128 * a symbol that has overridden this symbol (for example 129 * should two identical COMMON definitions be associated 130 * with the same move data), simply ignore this move 131 * element. 132 */ 133 if ((nmd.md_start == omdp->md_start) && 134 ((nmd.md_len == smdp->md_len) && 135 sdp->sd_file != isp->is_file)) 136 continue; 137 138 if ((nmd.md_start != omdp->md_start) && 139 ((smdp->md_start + smdp->md_len) <= lmdp->md_start)) 140 continue; 141 142 eprintf(ofl->ofl_lml, ERR_FATAL, 143 MSG_INTL(MSG_MOVE_OVERLAP), sdp->sd_file->ifl_name, 144 isp->is_name, demangle(sdp->sd_name), 145 EC_XWORD(nmd.md_start), EC_XWORD(nmd.md_len), 146 EC_XWORD(omdp->md_start), EC_XWORD(omdp->md_len)); 147 148 /* 149 * Indicate that an error has occurred, so that 150 * processing can be terminated once all move errors 151 * are flushed out. 152 */ 153 sdp->sd_flags1 |= FLG_SY1_OVERLAP; 154 return (1); 155 } 156 157 if (alist_append(&sdp->sd_move, &nmd, sizeof (Mv_desc), 158 AL_CNT_SDP_MOVE) == NULL) 159 return (S_ERROR); 160 } 161 return (1); 162 } 163 164 /* 165 * Validate a SHT_SUNW_move section. These are only processed from input 166 * relocatable objects. The move section entries are validated and any data 167 * structures required for later processing are created. 168 */ 169 uintptr_t 170 ld_process_move(Ofl_desc *ofl) 171 { 172 Aliste idx; 173 Is_desc *isp; 174 int errcnt = 0; 175 176 for (APLIST_TRAVERSE(ofl->ofl_ismove, idx, isp)) { 177 Ifl_desc *ifile = isp->is_file; 178 Move *mvp; 179 Xword i, num; 180 181 DBG_CALL(Dbg_move_input(ofl->ofl_lml, ifile->ifl_name)); 182 mvp = (Move *)isp->is_indata->d_buf; 183 184 if (isp->is_shdr->sh_entsize == 0) { 185 eprintf(ofl->ofl_lml, ERR_FATAL, 186 MSG_INTL(MSG_FIL_INVSHENTSIZE), 187 isp->is_file->ifl_name, isp->is_name, EC_XWORD(0)); 188 return (S_ERROR); 189 } 190 num = isp->is_shdr->sh_size / isp->is_shdr->sh_entsize; 191 192 for (i = 0; i < num; i++) { 193 Xword ndx = ELF_M_SYM(mvp->m_info); 194 Sym_desc *sdp; 195 Sym *sym; 196 197 if ((ndx >= (Xword) isp->is_file->ifl_symscnt) || 198 (ndx == 0)) { 199 eprintf(ofl->ofl_lml, ERR_FATAL, 200 MSG_INTL(MSG_PSYM_INVMINFO1), 201 isp->is_file->ifl_name, isp->is_name, i, 202 EC_XWORD(mvp->m_info)); 203 return (S_ERROR); 204 } 205 if (mvp->m_repeat == 0) { 206 eprintf(ofl->ofl_lml, ERR_FATAL, 207 MSG_INTL(MSG_PSYM_INVMREPEAT), 208 isp->is_file->ifl_name, isp->is_name, i, 209 EC_XWORD(mvp->m_repeat)); 210 return (S_ERROR); 211 } 212 213 sdp = isp->is_file->ifl_oldndx[ndx]; 214 DBG_CALL(Dbg_move_entry1(ofl->ofl_lml, 1, mvp, sdp)); 215 216 /* 217 * Validate that this entry has a valid size. 218 */ 219 /* LINTED */ 220 switch (ELF_M_SIZE(mvp->m_info)) { 221 case 1: case 2: case 4: case 8: 222 break; 223 default: 224 eprintf(ofl->ofl_lml, ERR_FATAL, 225 MSG_INTL(MSG_PSYM_INVMINFO2), 226 isp->is_file->ifl_name, isp->is_name, i, 227 EC_XWORD(mvp->m_info)); 228 return (S_ERROR); 229 } 230 231 /* 232 * If this is a global symbol, adjust the visibility. 233 */ 234 if (sdp->sd_aux && 235 ((sdp->sd_flags & FLG_SY_VISIBLE) == 0)) 236 ld_sym_adjust_vis(sdp, ofl); 237 238 sym = sdp->sd_sym; 239 240 if (sdp->sd_move == NULL) { 241 /* 242 * If this is the first move entry associated 243 * with this symbol, save the symbol on the 244 * partial symbol list, and initialize various 245 * state regarding this symbol. 246 */ 247 if (aplist_append(&ofl->ofl_parsyms, sdp, 248 AL_CNT_OFL_PARSYMS) == NULL) 249 return (S_ERROR); 250 251 /* 252 * Even if -zredlocsym is in effect, the local 253 * symbol used for partial initialization is 254 * kept. 255 */ 256 if ((ofl->ofl_flags & FLG_OF_REDLSYM) && 257 (ELF_ST_BIND(sym->st_info) == STB_LOCAL) && 258 (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) { 259 ofl->ofl_locscnt++; 260 if (st_insert(ofl->ofl_strtab, 261 sdp->sd_name) == -1) 262 return (S_ERROR); 263 } 264 265 /* 266 * Mark the input section associated with this 267 * partially initialized symbol. 268 * This is needed when the symbol 269 * the relocation entry uses symbol information 270 * not from the symbol entry. 271 * 272 * For executable, the following is 273 * needed only for expanded symbol. However, 274 * for shared object any partially non 275 * expanded symbols are moved from 276 * .bss/COMMON to .sunwbss. So the following are 277 * needed. 278 */ 279 if ((sym->st_shndx != SHN_UNDEF) && 280 (sym->st_shndx < SHN_LOPROC)) { 281 Is_desc *isc; 282 283 isc = ifile->ifl_isdesc[ sym->st_shndx]; 284 isc->is_flags |= FLG_IS_RELUPD; 285 286 if (sdp->sd_osym == NULL) { 287 if ((sdp->sd_osym = 288 libld_calloc(sizeof (Sym), 289 1)) == NULL) 290 return (S_ERROR); 291 *(sdp->sd_osym) = 292 *(sdp->sd_sym); 293 } 294 } 295 } 296 297 if (append_move_desc(ofl, sdp, mvp, isp) == S_ERROR) 298 return (S_ERROR); 299 300 if (sdp->sd_flags1 & FLG_SY1_OVERLAP) 301 errcnt++; 302 303 /* 304 * If this symbol is marked to be expanded, go to the 305 * next move entry. 306 */ 307 if (sdp->sd_flags & FLG_SY_PAREXPN) { 308 mvp++; 309 continue; 310 } 311 312 /* 313 * Decide whether this partial symbol is to be expanded 314 * or not. 315 * 316 * The symbol will be expanded if: 317 * a) '-z nopartial' is specified 318 * b) move entries covered entire symbol 319 * 320 * To expand an move entry, size of the symbol to be 321 * expanded need to be known to generate a file space. 322 * (see make_movesections().) 323 * 324 * Therefore the move entry can not be expanded 325 * if the partial symbol is a section symbol. 326 * (The size of the symbol may be unknown.) 327 * This may happen, for example, when a local symbol is 328 * reduced by the -zredlocsym. 329 * 330 * The following two if statements checks the 331 * if the move entry can be expanded or not. 332 */ 333 if (((ofl->ofl_flags & FLG_OF_STATIC) != 0) && 334 ((ofl->ofl_flags & FLG_OF_EXEC) != 0)) { 335 if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { 336 errcnt++; 337 eprintf(ofl->ofl_lml, ERR_FATAL, 338 MSG_INTL(MSG_PSYM_CANNOTEXPND), 339 sdp->sd_file->ifl_name, 340 isp->is_name, i, 341 MSG_INTL(MSG_PSYM_NOSTATIC)); 342 } else { 343 sdp->sd_flags |= FLG_SY_PAREXPN; 344 } 345 } else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) { 346 if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) { 347 eprintf(ofl->ofl_lml, ERR_WARNING, 348 MSG_INTL(MSG_PSYM_CANNOTEXPND), 349 sdp->sd_file->ifl_name, 350 isp->is_name, i, 351 MSG_ORIG(MSG_STR_EMPTY)); 352 } else { 353 sdp->sd_flags |= FLG_SY_PAREXPN; 354 } 355 } else if (((Xword)((sizeof (Move)) * 356 alist_nitems(sdp->sd_move)) > sym->st_size) && 357 (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) { 358 sdp->sd_flags |= FLG_SY_PAREXPN; 359 } 360 361 /* 362 * If a move entry exists that references a local 363 * symbol, and this symbol reference will eventually 364 * be assigned to the associated section, make sure the 365 * section symbol is available for relocating against 366 * at runtime. 367 */ 368 if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) && 369 (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) || 370 (ofl->ofl_flags & FLG_OF_REDLSYM))) { 371 Os_desc *osp = sdp->sd_isc->is_osdesc; 372 373 if (osp && 374 ((osp->os_flags & FLG_OS_OUTREL) == 0)) { 375 ofl->ofl_dynshdrcnt++; 376 osp->os_flags |= FLG_OS_OUTREL; 377 } else if ((sdp->sd_flags & 378 FLG_SY_PAREXPN) == 0) 379 ofl->ofl_flags1 |= FLG_OF1_BSSOREL; 380 } 381 mvp++; 382 } 383 } 384 385 if (errcnt != 0) 386 return (S_ERROR); 387 if (make_mvsections(ofl) == S_ERROR) 388 return (S_ERROR); 389 390 return (1); 391 } 392