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 2008 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 * 34 */ 35 static uintptr_t 36 make_mvsections(Ofl_desc *ofl) 37 { 38 Listnode * lnp1; 39 Psym_info * psym; 40 Word mv_nums = 0; 41 Xword align_parexpn = 0; /* for -z nopartial .data sec */ 42 size_t size_parexpn = 0; /* Size of parexpn section */ 43 44 /* 45 * Compute the size of the output move section 46 */ 47 for (LIST_TRAVERSE(&ofl->ofl_parsym, lnp1, psym)) { 48 Sym_desc * symd = psym->psym_symd; 49 Sym * sym; 50 Xword align_val; 51 52 sym = symd->sd_sym; 53 if (sym->st_shndx == SHN_COMMON) 54 align_val = sym->st_value; 55 else 56 align_val = 8; 57 if (symd->sd_flags & FLG_SY_PAREXPN) { 58 /* 59 * This global symbol goes 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 += psym->psym_num; 69 } 70 } 71 72 if (mv_nums != 0) { 73 if (ld_make_sunwmove(ofl, mv_nums) == S_ERROR) 74 return (S_ERROR); 75 } 76 77 /* 78 * Add empty area for partially initialized symbols. 79 * 80 * A special .data section is created when the '-z nopartial' 81 * option is in effect in order to receive the expanded data. 82 */ 83 if (size_parexpn) { 84 /* LINTED */ 85 if (ld_make_parexpn_data(ofl, size_parexpn, 86 align_parexpn) == S_ERROR) 87 return (S_ERROR); 88 } 89 return (1); 90 } 91 92 /* 93 * This function insert the Move_itm into the move list held by 94 * psymp. 95 */ 96 static uintptr_t 97 insert_mvitm(Ofl_desc *ofl, Psym_info *psymp, Mv_itm *itm) 98 { 99 Listnode * lnpc, *lnpp, *new; 100 Mv_itm * mvp; 101 102 /* 103 * If there is error on this symbol already, 104 * don't go any further. 105 */ 106 if ((psymp->psym_flag & FLG_PSYM_OVERLAP) != 0) 107 return (1); 108 109 if ((new = libld_calloc(sizeof (Listnode), 1)) == 0) 110 return (S_ERROR); 111 new->data = (void *) itm; 112 lnpp = lnpc = psymp->psym_mvs.head; 113 114 /* 115 * If this is the first, just update the 116 * head and tail. 117 */ 118 if (lnpc == (Listnode *) NULL) { 119 psymp->psym_mvs.tail = psymp->psym_mvs.head = new; 120 return (1); 121 } 122 123 for (LIST_TRAVERSE(&psymp->psym_mvs, lnpc, mvp)) { 124 Mv_itm * small, *large; 125 126 /* 127 * Check overlapping 128 * If there is no overlapping so far, 129 * check overlapping. 130 */ 131 if (itm->mv_start > mvp->mv_start) { 132 small = mvp; 133 large = itm; 134 } else { 135 small = itm; 136 large = mvp; 137 } 138 139 if ((itm->mv_start == mvp->mv_start) || 140 (small->mv_start + small->mv_length > large->mv_start)) { 141 eprintf(ofl->ofl_lml, ERR_FATAL, 142 MSG_INTL(MSG_PSYM_OVERLAP), 143 psymp->psym_symd->sd_file->ifl_name, 144 itm->mv_isp->is_name, 145 demangle(psymp->psym_symd->sd_name)); 146 psymp->psym_flag |= FLG_PSYM_OVERLAP; 147 return (1); 148 } 149 150 /* 151 * If passed, insert 152 */ 153 if (mvp->mv_start > itm->mv_start) { 154 new->next = lnpc; 155 if (lnpc == psymp->psym_mvs.head) { 156 psymp->psym_mvs.head = new; 157 } else 158 lnpp->next = new; 159 return (1); 160 } 161 162 /* 163 * If lnpc is the end, add 164 */ 165 if (lnpc->next == NULL) { 166 new->next = lnpc->next; 167 lnpc->next = new; 168 psymp->psym_mvs.tail = new; 169 return (1); 170 } 171 172 /* 173 * Go next 174 */ 175 lnpp = lnpc; 176 } 177 return (1); 178 } 179 180 /* 181 * Install the mv entry into the Psym_info 182 * 183 * Count coverage size 184 * If the coverage size meets the symbol size, 185 * mark that the symbol should be expanded. 186 * psymp->psym_symd->sd_flags |= FLG_SY_PAREXPN; 187 * 188 * Check overlapping 189 * If overlapping occurs, mark it at psymp->psym_flags 190 */ 191 static uintptr_t 192 install_mv(Ofl_desc *ofl, Psym_info *psymp, Move *mv, Is_desc *isp) 193 { 194 Mv_itm * mvitmp; 195 int cnt = mv->m_repeat; 196 int i; 197 198 if ((mvitmp = libld_calloc(sizeof (Mv_itm), cnt)) == 0) 199 return (S_ERROR); 200 201 mvitmp->mv_flag |= FLG_MV_OUTSECT; 202 psymp->psym_num += 1; 203 for (i = 0; i < cnt; i++) { 204 /* LINTED */ 205 mvitmp->mv_length = ELF_M_SIZE(mv->m_info); 206 mvitmp->mv_start = mv->m_poffset + i * 207 ((mv->m_stride + 1) * mvitmp->mv_length); 208 mvitmp->mv_ientry = mv; 209 mvitmp->mv_isp = isp; /* Mark input section */ 210 211 /* 212 * Insert the item 213 */ 214 if (insert_mvitm(ofl, psymp, mvitmp) == S_ERROR) 215 return (S_ERROR); 216 mvitmp++; 217 } 218 return (1); 219 } 220 221 /* 222 * Insert the given psym_info 223 */ 224 static uintptr_t 225 insert_psym(Ofl_desc *ofl, Psym_info *p1) 226 { 227 Listnode * lnpc, *lnpp, *new; 228 Psym_info * p2; 229 int g1 = 0; 230 231 if ((new = libld_calloc(sizeof (Listnode), 1)) == 0) 232 return (S_ERROR); 233 new->data = (void *) p1; 234 lnpp = lnpc = ofl->ofl_parsym.head; 235 if (ELF_ST_BIND(p1->psym_symd->sd_sym->st_info) != STB_LOCAL) 236 g1 = 1; 237 238 /* 239 * If this is the first, just update the 240 * head and tail. 241 */ 242 if (lnpc == (Listnode *) NULL) { 243 ofl->ofl_parsym.tail = ofl->ofl_parsym.head = new; 244 return (1); 245 } 246 247 for (LIST_TRAVERSE(&ofl->ofl_parsym, lnpc, p2)) { 248 int cmp1, g2, cmp; 249 250 if (ELF_ST_BIND(p2->psym_symd->sd_sym->st_info) != STB_LOCAL) 251 g2 = 1; 252 else 253 g2 = 0; 254 255 cmp1 = strcmp(p1->psym_symd->sd_name, p2->psym_symd->sd_name); 256 257 /* 258 * Compute position 259 */ 260 if (g1 == g2) 261 cmp = cmp1; 262 else if (g1 == 0) { 263 /* 264 * p1 is a local symbol. 265 * p2 is a global, so p1 passed. 266 */ 267 cmp = -1; 268 } else { 269 /* 270 * p1 is global 271 * p2 is still local. 272 * so try the next one. 273 * 274 * If lnpc is the end, add 275 */ 276 if (lnpc->next == NULL) { 277 new->next = lnpc->next; 278 lnpc->next = new; 279 ofl->ofl_parsym.tail = new; 280 break; 281 } 282 lnpp = lnpc; 283 continue; 284 } 285 286 /* 287 * If same, just add after 288 */ 289 if (cmp == 0) { 290 new->next = lnpc->next; 291 if (lnpc == ofl->ofl_parsym.tail) 292 ofl->ofl_parsym.tail = new; 293 lnpc->next = new; 294 break; 295 } 296 297 /* 298 * If passed, insert 299 */ 300 if (cmp < 0) { 301 new->next = lnpc; 302 if (lnpc == ofl->ofl_parsym.head) { 303 ofl->ofl_parsym.head = new; 304 } else 305 lnpp->next = new; 306 break; 307 } 308 309 /* 310 * If lnpc is the end, add 311 */ 312 if (lnpc->next == NULL) { 313 new->next = lnpc->next; 314 lnpc->next = new; 315 ofl->ofl_parsym.tail = new; 316 break; 317 } 318 319 /* 320 * Go next 321 */ 322 lnpp = lnpc; 323 } 324 return (1); 325 } 326 327 /* 328 * Mark the symbols 329 * 330 * Check only the symbols which came from the relocatable 331 * files.If partially initialized symbols come from 332 * shared objects, they can be ignored here because 333 * they are already processed when the shared object is 334 * created. 335 * 336 */ 337 uintptr_t 338 ld_sunwmove_preprocess(Ofl_desc *ofl) 339 { 340 Listnode * lnp; 341 Is_desc * isp; 342 Sym_desc * sdp; 343 Move * mv; 344 Psym_info * psym; 345 int errcnt = 0; 346 347 for (LIST_TRAVERSE(&ofl->ofl_ismove, lnp, isp)) { 348 Ifl_desc * ifile = isp->is_file; 349 Xword i, num; 350 351 DBG_CALL(Dbg_move_input(ofl->ofl_lml, ifile->ifl_name)); 352 mv = (Move *) isp->is_indata->d_buf; 353 354 if (isp->is_shdr->sh_entsize == 0) { 355 eprintf(ofl->ofl_lml, ERR_FATAL, 356 MSG_INTL(MSG_FIL_INVSHENTSIZE), 357 isp->is_file->ifl_name, isp->is_name, EC_XWORD(0)); 358 return (S_ERROR); 359 } 360 num = isp->is_shdr->sh_size/isp->is_shdr->sh_entsize; 361 for (i = 0; i < num; i++) { 362 Xword ndx = ELF_M_SYM(mv->m_info); 363 364 if ((ndx >= (Xword) isp->is_file->ifl_symscnt) || 365 (ndx == 0)) { 366 eprintf(ofl->ofl_lml, ERR_FATAL, 367 MSG_INTL(MSG_PSYM_INVMINFO1), 368 isp->is_file->ifl_name, isp->is_name, i, 369 EC_XWORD(mv->m_info)); 370 return (S_ERROR); 371 } 372 if (mv->m_repeat == 0) { 373 eprintf(ofl->ofl_lml, ERR_FATAL, 374 MSG_INTL(MSG_PSYM_INVMREPEAT), 375 isp->is_file->ifl_name, isp->is_name, i, 376 EC_XWORD(mv->m_repeat)); 377 return (S_ERROR); 378 } 379 380 sdp = isp->is_file->ifl_oldndx[ndx]; 381 DBG_CALL(Dbg_move_entry1(ofl->ofl_lml, 0, mv, sdp)); 382 383 /* 384 * Check if this entry has a valid size of not 385 */ 386 /* LINTED */ 387 switch (ELF_M_SIZE(mv->m_info)) { 388 case 1: case 2: case 4: case 8: 389 break; 390 default: 391 eprintf(ofl->ofl_lml, ERR_FATAL, 392 MSG_INTL(MSG_PSYM_INVMINFO2), 393 isp->is_file->ifl_name, isp->is_name, i, 394 EC_XWORD(mv->m_info)); 395 return (S_ERROR); 396 } 397 398 /* 399 * If this is a global symbol, adjust the visibility. 400 */ 401 if (sdp->sd_aux && 402 ((sdp->sd_flags & FLG_SY_VISIBLE) == 0)) 403 ld_sym_adjust_vis(sdp, ofl); 404 405 if (sdp->sd_psyminfo == (Psym_info *)NULL) { 406 /* 407 * Mark the symbol as partial, and install the 408 * symbol in the partial symbol list. 409 */ 410 if ((psym = 411 libld_calloc(sizeof (Psym_info), 1)) == 0) 412 return (S_ERROR); 413 psym->psym_symd = sdp; 414 sdp->sd_psyminfo = psym; 415 416 /* 417 * Even if the -zredlocsym is in effect, the 418 * local symbol used for partial initialization 419 * is kept. 420 */ 421 if ((ofl->ofl_flags & FLG_OF_REDLSYM) && 422 (ELF_ST_BIND(sdp->sd_sym->st_info) == 423 STB_LOCAL) && 424 (ELF_ST_TYPE(sdp->sd_sym->st_info) == 425 STT_OBJECT)) { 426 ofl->ofl_locscnt++; 427 if (st_insert(ofl->ofl_strtab, 428 sdp->sd_name) == -1) 429 return (S_ERROR); 430 } 431 if (insert_psym(ofl, psym) == 0) 432 return (S_ERROR); 433 434 /* 435 * Mark the input section which the partially 436 * initialized * symbol is defined. 437 * This is needed when the symbol 438 * the relocation entry uses symbol information 439 * not from the symbol entry. 440 * 441 * For executable, the following is 442 * needed only for expanded symbol. However, 443 * for shared object * any partially non 444 * expanded symbols are moved * from 445 * .bss/COMMON to .sunwbss. So the following are 446 * needed. 447 */ 448 if ((sdp->sd_sym->st_shndx != SHN_UNDEF) && 449 (sdp->sd_sym->st_shndx < SHN_LOPROC)) { 450 Is_desc * isym = ifile->ifl_isdesc[ 451 sdp->sd_sym->st_shndx]; 452 isym->is_flags |= FLG_IS_RELUPD; 453 if (sdp->sd_osym == (Sym *) 0) { 454 if ((sdp->sd_osym = 455 libld_calloc(sizeof (Sym), 456 1)) == 0) 457 return (S_ERROR); 458 *(sdp->sd_osym) = 459 *(sdp->sd_sym); 460 } 461 } 462 } else 463 psym = sdp->sd_psyminfo; 464 465 if (install_mv(ofl, psym, mv, isp) == S_ERROR) 466 return (S_ERROR); 467 if ((psym->psym_flag & FLG_PSYM_OVERLAP) != 0) 468 errcnt++; 469 470 /* 471 * If this symbol is marked to be 472 * expanded, go to the next moveentry. 473 */ 474 if (sdp->sd_flags & FLG_SY_PAREXPN) { 475 mv++; 476 continue; 477 } 478 479 /* 480 * Decide whether this partial symbol is to be expanded 481 * or not. 482 * 483 * The symbol will be expanded if: 484 * a) '-z nopartial' is specified 485 * b) move entries covered entire symbol 486 * 487 * To expand an move entry, size of the symbol to be 488 * expanded need to be known to generate a file space. 489 * (see make_movesections().) 490 * 491 * Therefore the move entry can not be expanded 492 * if the partial symbol is a section symbol. 493 * (The size of the symbol may be unknown.) 494 * This may happen, for example, when a local symbol is 495 * reduced by the -zredlocsym. 496 * 497 * The following two if statements checks the 498 * if the move entry can be expanded or not. 499 */ 500 if (((ofl->ofl_flags & FLG_OF_STATIC) != 0) && 501 ((ofl->ofl_flags & FLG_OF_EXEC) != 0)) { 502 if (ELF_ST_TYPE(sdp->sd_sym->st_info) == 503 STT_SECTION) { 504 errcnt++; 505 eprintf(ofl->ofl_lml, ERR_FATAL, 506 MSG_INTL(MSG_PSYM_CANNOTEXPND), 507 psym->psym_symd->sd_file->ifl_name, 508 isp->is_name, i, 509 MSG_INTL(MSG_PSYM_NOSTATIC)); 510 } else { 511 sdp->sd_flags |= FLG_SY_PAREXPN; 512 } 513 } else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) { 514 if (ELF_ST_TYPE(sdp->sd_sym->st_info) == 515 STT_SECTION) { 516 eprintf(ofl->ofl_lml, ERR_WARNING, 517 MSG_INTL(MSG_PSYM_CANNOTEXPND), 518 psym->psym_symd->sd_file->ifl_name, 519 isp->is_name, i, 520 MSG_ORIG(MSG_STR_EMPTY)); 521 } else { 522 sdp->sd_flags |= FLG_SY_PAREXPN; 523 } 524 } else if ( 525 ((Xword)((sizeof (Move)) * psym->psym_num) > 526 psym->psym_symd->sd_sym->st_size) && 527 (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_OBJECT)) { 528 sdp->sd_flags |= FLG_SY_PAREXPN; 529 } 530 531 /* 532 * If a move section exists that references .bss, make 533 * sure a section symbol for .bss is introduced into 534 * the .dynsym. 535 */ 536 if (((sdp->sd_flags & FLG_SY_PAREXPN) == 0) && 537 ((ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL) || 538 ((sdp->sd_flags1 & FLG_SY1_HIDDEN) && 539 (ofl->ofl_flags & FLG_OF_PROCRED)))) { 540 ofl->ofl_flags1 |= FLG_OF1_BSSOREL; 541 } 542 mv++; 543 } 544 } 545 546 if (errcnt != 0) 547 return (S_ERROR); 548 if (make_mvsections(ofl) == S_ERROR) 549 return (S_ERROR); 550 551 return (1); 552 } 553