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
make_mvsections(Ofl_desc * ofl)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
append_move_desc(Ofl_desc * ofl,Sym_desc * sdp,Move * mvp,Is_desc * isp)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
ld_process_move(Ofl_desc * ofl)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(1,
292 sizeof (Sym))) == 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