xref: /illumos-gate/usr/src/cmd/sgs/libld/common/sunwmove.c (revision 842727c2f41f01b380de4f5e787d905702870f23)
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_flags1 |= FLG_SY1_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_flags1 & FLG_SY1_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->ofl_flags & FLG_OF_STATIC) != 0) &&
339 			    ((ofl->ofl_flags & FLG_OF_EXEC) != 0)) {
340 				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
341 					errcnt++;
342 					eprintf(ofl->ofl_lml, ERR_FATAL,
343 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
344 					    sdp->sd_file->ifl_name,
345 					    EC_WORD(isp->is_scnndx),
346 					    isp->is_name, i,
347 					    MSG_INTL(MSG_PSYM_NOSTATIC));
348 				} else {
349 					sdp->sd_flags |= FLG_SY_PAREXPN;
350 				}
351 			} else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) {
352 				if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
353 					eprintf(ofl->ofl_lml, ERR_WARNING,
354 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
355 					    sdp->sd_file->ifl_name,
356 					    EC_WORD(isp->is_scnndx),
357 					    isp->is_name, i,
358 					    MSG_ORIG(MSG_STR_EMPTY));
359 				} else {
360 					sdp->sd_flags |= FLG_SY_PAREXPN;
361 				}
362 			} else if (((Xword)((sizeof (Move)) *
363 			    alist_nitems(sdp->sd_move)) > sym->st_size) &&
364 			    (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
365 				sdp->sd_flags |= FLG_SY_PAREXPN;
366 			}
367 
368 			/*
369 			 * If a move entry exists that references a local
370 			 * symbol, and this symbol reference will eventually
371 			 * be assigned to the associated section, make sure the
372 			 * section symbol is available for relocating against
373 			 * at runtime.
374 			 */
375 			if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
376 			    (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
377 			    (ofl->ofl_flags & FLG_OF_REDLSYM))) {
378 				Os_desc *osp = sdp->sd_isc->is_osdesc;
379 
380 				if (osp &&
381 				    ((osp->os_flags & FLG_OS_OUTREL) == 0)) {
382 					ofl->ofl_dynshdrcnt++;
383 					osp->os_flags |= FLG_OS_OUTREL;
384 				} else if ((sdp->sd_flags &
385 				    FLG_SY_PAREXPN) == 0)
386 					ofl->ofl_flags1 |= FLG_OF1_BSSOREL;
387 			}
388 			mvp++;
389 		}
390 	}
391 
392 	if (errcnt != 0)
393 		return (S_ERROR);
394 	if (make_mvsections(ofl) == S_ERROR)
395 		return (S_ERROR);
396 
397 	return (1);
398 }
399