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