xref: /illumos-gate/usr/src/cmd/sgs/libld/common/sunwmove.c (revision fbd1c0dae6f4a2ccc2ce0527c7f19d3dd5ea90b8)
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 2006 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 (ld_make_sunwmove(ofl, mv_nums) == S_ERROR)
91 			return (S_ERROR);
92 	}
93 
94 	/*
95 	 * Generate the .sunwbss section now that we know its size and
96 	 * alignment.
97 	 */
98 	if (size_sunwbss) {
99 		if (ld_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 (ld_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(Ofl_desc *ofl, 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(ofl->ofl_lml, ERR_FATAL,
170 			    MSG_INTL(MSG_PSYM_OVERLAP),
171 			    psymp->psym_symd->sd_file->ifl_name,
172 			    itm->mv_isp->is_name,
173 			    demangle(psymp->psym_symd->sd_name));
174 			psymp->psym_flag |= FLG_PSYM_OVERLAP;
175 			return (1);
176 		}
177 
178 		/*
179 		 * If passed, insert
180 		 */
181 		if (mvp->mv_start > itm->mv_start) {
182 			new->next = lnpc;
183 			if (lnpc == psymp->psym_mvs.head) {
184 				psymp->psym_mvs.head = new;
185 			} else
186 				lnpp->next = new;
187 			return (1);
188 		}
189 
190 		/*
191 		 * If lnpc is the end, add
192 		 */
193 		if (lnpc->next == NULL) {
194 			new->next = lnpc->next;
195 			lnpc->next = new;
196 			psymp->psym_mvs.tail = new;
197 			return (1);
198 		}
199 
200 		/*
201 		 * Go next
202 		 */
203 		lnpp = lnpc;
204 	}
205 	return (1);
206 }
207 
208 /*
209  * Install the mv entry into the Psym_info
210  *
211  * Count coverage size
212  *	If the coverage size meets the symbol size,
213  *	mark that the symbol should be expanded.
214  *	psymp->psym_symd->sd_flags |= FLG_SY_PAREXPN;
215  *
216  * Check overlapping
217  *	If overlapping occurs, mark it at psymp->psym_flags
218  */
219 static uintptr_t
220 install_mv(Ofl_desc *ofl, Psym_info *psymp, Move *mv, Is_desc *isp)
221 {
222 	Mv_itm *	mvitmp;
223 	int 		cnt = mv->m_repeat;
224 	int 		i;
225 
226 	if ((mvitmp = libld_calloc(sizeof (Mv_itm), cnt)) == 0)
227 		return (S_ERROR);
228 
229 	mvitmp->mv_flag |= FLG_MV_OUTSECT;
230 	psymp->psym_num += 1;
231 	for (i = 0; i < cnt; i++) {
232 		/* LINTED */
233 		mvitmp->mv_length = ELF_M_SIZE(mv->m_info);
234 		mvitmp->mv_start = mv->m_poffset +
235 			i * ((mv->m_stride + 1) * mvitmp->mv_length);
236 		mvitmp->mv_ientry = mv;
237 		mvitmp->mv_isp = isp;		/* Mark input section */
238 
239 		/*
240 		 * Insert the item
241 		 */
242 		if (insert_mvitm(ofl, psymp, mvitmp) == S_ERROR)
243 			return (S_ERROR);
244 		mvitmp++;
245 	}
246 	return (1);
247 }
248 
249 /*
250  * Insert the given psym_info
251  */
252 static uintptr_t
253 insert_psym(Ofl_desc *ofl, Psym_info *p1)
254 {
255 	Listnode *	lnpc, *lnpp, *new;
256 	Psym_info *	p2;
257 	int		g1 = 0;
258 
259 	if ((new = libld_calloc(sizeof (Listnode), 1)) == 0)
260 		return (S_ERROR);
261 	new->data = (void *) p1;
262 	lnpp = lnpc = ofl->ofl_parsym.head;
263 	if (ELF_ST_BIND(p1->psym_symd->sd_sym->st_info) != STB_LOCAL)
264 		g1 = 1;
265 
266 	/*
267 	 * If this is the first, just update the
268 	 * head and tail.
269 	 */
270 	if (lnpc == (Listnode *) NULL) {
271 		ofl->ofl_parsym.tail =
272 			ofl->ofl_parsym.head = new;
273 		return (1);
274 	}
275 
276 	for (LIST_TRAVERSE(&ofl->ofl_parsym, lnpc, p2)) {
277 		int cmp1, g2, cmp;
278 
279 		if (ELF_ST_BIND(p2->psym_symd->sd_sym->st_info) != STB_LOCAL)
280 			g2 = 1;
281 		else
282 			g2 = 0;
283 
284 		cmp1 = strcmp(p1->psym_symd->sd_name, p2->psym_symd->sd_name);
285 
286 		/*
287 		 * Compute position
288 		 */
289 		if (g1 == g2)
290 			cmp = cmp1;
291 		else if (g1 == 0) {
292 			/*
293 			 * p1 is a local symbol.
294 			 * p2 is a global, so p1 passed.
295 			 */
296 			cmp = -1;
297 		} else {
298 			/*
299 			 * p1 is global
300 			 * p2 is still local.
301 			 * so try the next one.
302 			 *
303 			 * If lnpc is the end, add
304 			 */
305 			if (lnpc->next == NULL) {
306 				new->next = lnpc->next;
307 				lnpc->next = new;
308 				ofl->ofl_parsym.tail = new;
309 				break;
310 			}
311 			lnpp = lnpc;
312 			continue;
313 		}
314 
315 		/*
316 		 * If same, just add after
317 		 */
318 		if (cmp == 0) {
319 			new->next = lnpc->next;
320 			if (lnpc == ofl->ofl_parsym.tail)
321 				ofl->ofl_parsym.tail = new;
322 			lnpc->next = new;
323 			break;
324 		}
325 
326 		/*
327 		 * If passed, insert
328 		 */
329 		if (cmp < 0) {
330 			new->next = lnpc;
331 			if (lnpc == ofl->ofl_parsym.head) {
332 				ofl->ofl_parsym.head = new;
333 			} else
334 				lnpp->next = new;
335 			break;
336 		}
337 
338 		/*
339 		 * If lnpc is the end, add
340 		 */
341 		if (lnpc->next == NULL) {
342 			new->next = lnpc->next;
343 			lnpc->next = new;
344 			ofl->ofl_parsym.tail = new;
345 			break;
346 		}
347 
348 		/*
349 		 * Go next
350 		 */
351 		lnpp = lnpc;
352 	}
353 	return (1);
354 }
355 
356 /*
357  * Mark the symbols
358  *
359  * Check only the symbols which came from the relocatable
360  * files.If partially initialized symbols come from
361  * shared objects, they can be ignored here because
362  * they are already processed when the shared object is
363  * created.
364  *
365  */
366 uintptr_t
367 ld_sunwmove_preprocess(Ofl_desc *ofl)
368 {
369 	Listnode *	lnp;
370 	Is_desc *	isp;
371 	Sym_desc *	sdp;
372 	Move *		mv;
373 	Psym_info *	psym;
374 	int 		errcnt = 0;
375 
376 	for (LIST_TRAVERSE(&ofl->ofl_ismove, lnp, isp)) {
377 		Ifl_desc *	ifile = isp->is_file;
378 		Xword		i, num;
379 
380 		DBG_CALL(Dbg_move_input(ofl->ofl_lml, ifile->ifl_name));
381 		mv = (Move *) isp->is_indata->d_buf;
382 
383 		if (isp->is_shdr->sh_entsize == 0) {
384 			eprintf(ofl->ofl_lml, ERR_FATAL,
385 			    MSG_INTL(MSG_FIL_INVSHENTSIZE),
386 			    isp->is_file->ifl_name, isp->is_name, EC_XWORD(0));
387 			return (S_ERROR);
388 		}
389 		num = isp->is_shdr->sh_size/isp->is_shdr->sh_entsize;
390 		for (i = 0; i < num; i++) {
391 			Xword 	ndx = ELF_M_SYM(mv->m_info);
392 
393 			if ((ndx >= (Xword) isp->is_file->ifl_symscnt) ||
394 			    (ndx == 0)) {
395 				eprintf(ofl->ofl_lml, ERR_FATAL,
396 				    MSG_INTL(MSG_PSYM_INVMINFO1),
397 				    isp->is_file->ifl_name, isp->is_name, i,
398 				    EC_XWORD(mv->m_info));
399 				return (S_ERROR);
400 			}
401 			if (mv->m_repeat == 0) {
402 				eprintf(ofl->ofl_lml, ERR_FATAL,
403 				    MSG_INTL(MSG_PSYM_INVMREPEAT),
404 				    isp->is_file->ifl_name, isp->is_name, i,
405 				    EC_XWORD(mv->m_repeat));
406 				return (S_ERROR);
407 			}
408 
409 			sdp = isp->is_file->ifl_oldndx[ndx];
410 			DBG_CALL(Dbg_move_entry1(ofl->ofl_lml, 0, mv, sdp));
411 
412 			/*
413 			 * Check if this entry has a valid size of not
414 			 */
415 			/* LINTED */
416 			switch (ELF_M_SIZE(mv->m_info)) {
417 			case 1: case 2: case 4: case 8:
418 				break;
419 			default:
420 				eprintf(ofl->ofl_lml, ERR_FATAL,
421 				    MSG_INTL(MSG_PSYM_INVMINFO2),
422 				    isp->is_file->ifl_name, isp->is_name, i,
423 				    EC_XWORD(mv->m_info));
424 				return (S_ERROR);
425 			}
426 
427 			/*
428 			 * If this is a global symbol, adjust the visibility.
429 			 */
430 			if (sdp->sd_aux &&
431 			    ((sdp->sd_flags & FLG_SY_VISIBLE) == 0))
432 				ld_sym_adjust_vis(sdp, ofl);
433 
434 			if (sdp->sd_psyminfo == (Psym_info *)NULL) {
435 				/*
436 				 * Mark the symbol as partial, and install the
437 				 * symbol in the partial symbol list.
438 				 */
439 				if ((psym =
440 				    libld_calloc(sizeof (Psym_info), 1)) == 0)
441 					return (S_ERROR);
442 				psym->psym_symd = sdp;
443 				sdp->sd_psyminfo = psym;
444 
445 				/*
446 				 * Even if the -zredlocsym is in effect, the
447 				 * local symbol used for partial initialization
448 				 * is kept.
449 				 */
450 				if ((ofl->ofl_flags1 & FLG_OF1_REDLSYM) &&
451 				    (ELF_ST_BIND(sdp->sd_sym->st_info) ==
452 				    STB_LOCAL) &&
453 				    (ELF_ST_TYPE(sdp->sd_sym->st_info) ==
454 				    STT_OBJECT)) {
455 					ofl->ofl_locscnt++;
456 					if (st_insert(ofl->ofl_strtab,
457 					    sdp->sd_name) == -1)
458 						return (S_ERROR);
459 				}
460 				if (insert_psym(ofl, psym) == 0)
461 					return (S_ERROR);
462 
463 				/*
464 				 * Mark the input section which the partially
465 				 * initialized * symbol is defined.
466 				 * This is needed when the symbol
467 				 * the relocation entry uses symbol information
468 				 * not from the symbol entry.
469 				 *
470 				 * For executable, the following is
471 				 * needed only for expanded symbol. However,
472 				 * for shared object * any partially non
473 				 * expanded symbols are moved * from
474 				 * .bss/COMMON to .sunwbss. So the following are
475 				 * needed.
476 				 */
477 				if ((sdp->sd_sym->st_shndx != SHN_UNDEF) &&
478 				    (sdp->sd_sym->st_shndx < SHN_LOPROC)) {
479 					Is_desc * isym = ifile->ifl_isdesc[
480 					    sdp->sd_sym->st_shndx];
481 					isym->is_flags |= FLG_IS_RELUPD;
482 					if (sdp->sd_osym == (Sym *) 0) {
483 						if ((sdp->sd_osym =
484 						    libld_calloc(sizeof (Sym),
485 						    1)) == 0)
486 							return (S_ERROR);
487 						*(sdp->sd_osym) =
488 							*(sdp->sd_sym);
489 					}
490 				}
491 			} else
492 				psym = sdp->sd_psyminfo;
493 
494 			if (install_mv(ofl, psym, mv, isp) == S_ERROR)
495 				return (S_ERROR);
496 			if ((psym->psym_flag & FLG_PSYM_OVERLAP) != 0)
497 				errcnt++;
498 
499 			/*
500 			 * If this symbol is marked to be
501 			 * expanded, go to the next moveentry.
502 			 */
503 			if (sdp->sd_flags & FLG_SY_PAREXPN) {
504 				mv++;
505 				continue;
506 			}
507 
508 			/*
509 			 * Decide whether this partial symbol is to be expanded
510 			 * or not.
511 			 *
512 			 * The symbol will be expanded if:
513 			 *	a) '-z nopartial' is specified
514 			 *	b) move entries covered entire symbol
515 			 *
516 			 * To expand an move entry, size of the symbol to be
517 			 * expanded need to be known to generate a file space.
518 			 * (see make_movesections().)
519 			 *
520 			 * Therefore the move entry can not be expanded
521 			 * if the partial symbol is a section symbol.
522 			 * (The size of the symbol may be unknown.)
523 			 * This may happen, for example, when a local symbol is
524 			 * reduced by the -zredlocsym.
525 			 *
526 			 * The following two if statements checks the
527 			 * if the move entry can be expanded or not.
528 			 */
529 			if (((ofl->ofl_flags & FLG_OF_STATIC) != 0) &&
530 			    ((ofl->ofl_flags & FLG_OF_EXEC) != 0)) {
531 				if (ELF_ST_TYPE(sdp->sd_sym->st_info) ==
532 				    STT_SECTION) {
533 					errcnt++;
534 					eprintf(ofl->ofl_lml, ERR_FATAL,
535 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
536 					    psym->psym_symd->sd_file->ifl_name,
537 					    isp->is_name, i,
538 					    MSG_INTL(MSG_PSYM_NOSTATIC));
539 				} else {
540 					sdp->sd_flags |= FLG_SY_PAREXPN;
541 				}
542 			} else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) {
543 				if (ELF_ST_TYPE(sdp->sd_sym->st_info) ==
544 				    STT_SECTION) {
545 					eprintf(ofl->ofl_lml, ERR_WARNING,
546 					    MSG_INTL(MSG_PSYM_CANNOTEXPND),
547 					    psym->psym_symd->sd_file->ifl_name,
548 					    isp->is_name, i,
549 					    MSG_ORIG(MSG_STR_EMPTY));
550 				} else {
551 					sdp->sd_flags |= FLG_SY_PAREXPN;
552 				}
553 			} else if (
554 			    ((Xword)((sizeof (Move)) * psym->psym_num) >
555 			    psym->psym_symd->sd_sym->st_size) &&
556 			    (ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_OBJECT)) {
557 				sdp->sd_flags |= FLG_SY_PAREXPN;
558 			}
559 
560 			/*
561 			 * If a move section exists that references .bss, make
562 			 * sure a section symbol for .bss is introduced into
563 			 * the .dynsym.
564 			 */
565 			if (((sdp->sd_flags & FLG_SY_PAREXPN) == 0) &&
566 			    ((ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL) ||
567 			    ((sdp->sd_flags1 & FLG_SY1_LOCL) &&
568 			    (ofl->ofl_flags & FLG_OF_PROCRED)))) {
569 				ofl->ofl_flags1 |= FLG_OF1_BSSOREL;
570 			}
571 			mv++;
572 		}
573 	}
574 
575 	if (errcnt != 0)
576 		return (S_ERROR);
577 	if (make_mvsections(ofl) == S_ERROR)
578 		return (S_ERROR);
579 
580 	return (1);
581 }
582