xref: /illumos-gate/usr/src/cmd/sgs/libld/common/sunwmove.c (revision 7a088f03b431bdffa96c3b2175964d4d38420caa)
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