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