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