Home | History | Annotate | Download | only in common
      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 			    EC_WORD(isp->is_scnndx),
    145 			    isp->is_name, demangle(sdp->sd_name),
    146 			    EC_XWORD(nmd.md_start), EC_XWORD(nmd.md_len),
    147 			    EC_XWORD(omdp->md_start), EC_XWORD(omdp->md_len));
    148 
    149 			/*
    150 			 * Indicate that an error has occurred, so that
    151 			 * processing can be terminated once all move errors
    152 			 * are flushed out.
    153 			 */
    154 			sdp->sd_flags |= FLG_SY_OVERLAP;
    155 			return (1);
    156 		}
    157 
    158 		if (alist_append(&sdp->sd_move, &nmd, sizeof (Mv_desc),
    159 		    AL_CNT_SDP_MOVE) == NULL)
    160 			return (S_ERROR);
    161 	}
    162 	return (1);
    163 }
    164 
    165 /*
    166  * Validate a SHT_SUNW_move section.  These are only processed from input
    167  * relocatable objects.  The move section entries are validated and any data
    168  * structures required for later processing are created.
    169  */
    170 uintptr_t
    171 ld_process_move(Ofl_desc *ofl)
    172 {
    173 	Aliste		idx;
    174 	Is_desc		*isp;
    175 	int 		errcnt = 0;
    176 
    177 	for (APLIST_TRAVERSE(ofl->ofl_ismove, idx, isp)) {
    178 		Ifl_desc	*ifile = isp->is_file;
    179 		Move		*mvp;
    180 		Xword		i, num;
    181 
    182 		DBG_CALL(Dbg_move_input(ofl->ofl_lml, ifile->ifl_name));
    183 		mvp = (Move *)isp->is_indata->d_buf;
    184 
    185 		if (isp->is_shdr->sh_entsize == 0) {
    186 			eprintf(ofl->ofl_lml, ERR_FATAL,
    187 			    MSG_INTL(MSG_FIL_INVSHENTSIZE),
    188 			    isp->is_file->ifl_name, EC_WORD(isp->is_scnndx),
    189 			    isp->is_name, EC_XWORD(0));
    190 			return (S_ERROR);
    191 		}
    192 		num = isp->is_shdr->sh_size / isp->is_shdr->sh_entsize;
    193 
    194 		for (i = 0; i < num; i++) {
    195 			Xword 		ndx = ELF_M_SYM(mvp->m_info);
    196 			Sym_desc	*sdp;
    197 			Sym		*sym;
    198 
    199 			if ((ndx >= (Xword) isp->is_file->ifl_symscnt) ||
    200 			    (ndx == 0)) {
    201 				eprintf(ofl->ofl_lml, ERR_FATAL,
    202 				    MSG_INTL(MSG_PSYM_INVMINFO1),
    203 				    isp->is_file->ifl_name,
    204 				    EC_WORD(isp->is_scnndx), isp->is_name, i,
    205 				    EC_XWORD(mvp->m_info));
    206 				return (S_ERROR);
    207 			}
    208 			if (mvp->m_repeat == 0) {
    209 				eprintf(ofl->ofl_lml, ERR_FATAL,
    210 				    MSG_INTL(MSG_PSYM_INVMREPEAT),
    211 				    isp->is_file->ifl_name,
    212 				    EC_WORD(isp->is_scnndx), isp->is_name, i,
    213 				    EC_XWORD(mvp->m_repeat));
    214 				return (S_ERROR);
    215 			}
    216 
    217 			sdp = isp->is_file->ifl_oldndx[ndx];
    218 			DBG_CALL(Dbg_move_entry1(ofl->ofl_lml, 1, mvp, sdp));
    219 
    220 			/*
    221 			 * Validate that this entry has a valid size.
    222 			 */
    223 			/* LINTED */
    224 			switch (ELF_M_SIZE(mvp->m_info)) {
    225 			case 1: case 2: case 4: case 8:
    226 				break;
    227 			default:
    228 				eprintf(ofl->ofl_lml, ERR_FATAL,
    229 				    MSG_INTL(MSG_PSYM_INVMINFO2),
    230 				    isp->is_file->ifl_name,
    231 				    EC_WORD(isp->is_scnndx), isp->is_name, i,
    232 				    EC_XWORD(mvp->m_info));
    233 				return (S_ERROR);
    234 			}
    235 
    236 			/*
    237 			 * If this is a global symbol, adjust the visibility.
    238 			 */
    239 			if (sdp->sd_aux &&
    240 			    ((sdp->sd_flags & FLG_SY_VISIBLE) == 0))
    241 				ld_sym_adjust_vis(sdp, ofl);
    242 
    243 			sym = sdp->sd_sym;
    244 
    245 			if (sdp->sd_move == NULL) {
    246 				/*
    247 				 * If this is the first move entry associated
    248 				 * with this symbol, save the symbol on the
    249 				 * partial symbol list, and initialize various
    250 				 * state regarding this symbol.
    251 				 */
    252 				if (aplist_append(&ofl->ofl_parsyms, sdp,
    253 				    AL_CNT_OFL_PARSYMS) == NULL)
    254 					return (S_ERROR);
    255 
    256 				/*
    257 				 * Even if -zredlocsym is in effect, the local
    258 				 * symbol used for partial initialization is
    259 				 * kept.
    260 				 */
    261 				if ((ofl->ofl_flags & FLG_OF_REDLSYM) &&
    262 				    (ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
    263 				    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
    264 					ofl->ofl_locscnt++;
    265 					if (st_insert(ofl->ofl_strtab,
    266 					    sdp->sd_name) == -1)
    267 						return (S_ERROR);
    268 				}
    269 
    270 				/*
    271 				 * Mark the input section associated with this
    272 				 * partially initialized symbol.
    273 				 * This is needed when the symbol
    274 				 * the relocation entry uses symbol information
    275 				 * not from the symbol entry.
    276 				 *
    277 				 * For executable, the following is
    278 				 * needed only for expanded symbol. However,
    279 				 * for shared object any partially non
    280 				 * expanded symbols are moved from
    281 				 * .bss/COMMON to .sunwbss. So the following are
    282 				 * needed.
    283 				 */
    284 				if ((sym->st_shndx != SHN_UNDEF) &&
    285 				    (sym->st_shndx < SHN_LOPROC)) {
    286 					Is_desc	*isc;
    287 
    288 					isc = ifile->ifl_isdesc[ sym->st_shndx];
    289 					isc->is_flags |= FLG_IS_RELUPD;
    290 
    291 					if (sdp->sd_osym == NULL) {
    292 						if ((sdp->sd_osym =
    293 						    libld_calloc(sizeof (Sym),
    294 						    1)) == NULL)
    295 							return (S_ERROR);
    296 						*(sdp->sd_osym) =
    297 						    *(sdp->sd_sym);
    298 					}
    299 				}
    300 			}
    301 
    302 			if (append_move_desc(ofl, sdp, mvp, isp) == S_ERROR)
    303 				return (S_ERROR);
    304 
    305 			if (sdp->sd_flags & FLG_SY_OVERLAP)
    306 				errcnt++;
    307 
    308 			/*
    309 			 * If this symbol is marked to be expanded, go to the
    310 			 * next move entry.
    311 			 */
    312 			if (sdp->sd_flags & FLG_SY_PAREXPN) {
    313 				mvp++;
    314 				continue;
    315 			}
    316 
    317 			/*
    318 			 * Decide whether this partial symbol is to be expanded
    319 			 * or not.
    320 			 *
    321 			 * The symbol will be expanded if:
    322 			 *	a) '-z nopartial' is specified
    323 			 *	b) move entries covered entire symbol
    324 			 *
    325 			 * To expand an move entry, size of the symbol to be
    326 			 * expanded need to be known to generate a file space.
    327 			 * (see make_movesections().)
    328 			 *
    329 			 * Therefore the move entry can not be expanded
    330 			 * if the partial symbol is a section symbol.
    331 			 * (The size of the symbol may be unknown.)
    332 			 * This may happen, for example, when a local symbol is
    333 			 * reduced by the -zredlocsym.
    334 			 *
    335 			 * The following two if statements checks the
    336 			 * if the move entry can be expanded or not.
    337 			 */
    338 			if (OFL_IS_STATIC_EXEC(ofl)) {
    339 				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
    340 					errcnt++;
    341 					eprintf(ofl->ofl_lml, ERR_FATAL,
    342 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
    343 					    sdp->sd_file->ifl_name,
    344 					    EC_WORD(isp->is_scnndx),
    345 					    isp->is_name, i,
    346 					    MSG_INTL(MSG_PSYM_NOSTATIC));
    347 				} else {
    348 					sdp->sd_flags |= FLG_SY_PAREXPN;
    349 				}
    350 			} else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) {
    351 				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
    352 					eprintf(ofl->ofl_lml, ERR_WARNING,
    353 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
    354 					    sdp->sd_file->ifl_name,
    355 					    EC_WORD(isp->is_scnndx),
    356 					    isp->is_name, i,
    357 					    MSG_ORIG(MSG_STR_EMPTY));
    358 				} else {
    359 					sdp->sd_flags |= FLG_SY_PAREXPN;
    360 				}
    361 			} else if (((Xword)((sizeof (Move)) *
    362 			    alist_nitems(sdp->sd_move)) > sym->st_size) &&
    363 			    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
    364 				sdp->sd_flags |= FLG_SY_PAREXPN;
    365 			}
    366 
    367 			/*
    368 			 * If a move entry exists that references a local
    369 			 * symbol, and this symbol reference will eventually
    370 			 * be assigned to the associated section, make sure the
    371 			 * section symbol is available for relocating against
    372 			 * at runtime.
    373 			 */
    374 			if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
    375 			    (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
    376 			    (ofl->ofl_flags & FLG_OF_REDLSYM))) {
    377 				Os_desc *osp = sdp->sd_isc->is_osdesc;
    378 
    379 				if (osp &&
    380 				    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
    381 					ofl->ofl_dynshdrcnt++;
    382 					osp->os_flags |= FLG_OS_OUTREL;
    383 				} else if ((sdp->sd_flags &
    384 				    FLG_SY_PAREXPN) == 0)
    385 					ofl->ofl_flags1 |= FLG_OF1_BSSOREL;
    386 			}
    387 			mvp++;
    388 		}
    389 	}
    390 
    391 	if (errcnt != 0)
    392 		return (S_ERROR);
    393 	if (make_mvsections(ofl) == S_ERROR)
    394 		return (S_ERROR);
    395 
    396 	return (1);
    397 }
    398