File: | src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c |
Warning: | line 1178, column 4 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* .eh_frame section optimization. | |||
2 | Copyright 2001, 2002, 2003 Free Software Foundation, Inc. | |||
3 | Written by Jakub Jelinek <jakub@redhat.com>. | |||
4 | ||||
5 | This file is part of BFD, the Binary File Descriptor library. | |||
6 | ||||
7 | This program is free software; you can redistribute it and/or modify | |||
8 | it under the terms of the GNU General Public License as published by | |||
9 | the Free Software Foundation; either version 2 of the License, or | |||
10 | (at your option) any later version. | |||
11 | ||||
12 | This program is distributed in the hope that it will be useful, | |||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
15 | GNU General Public License for more details. | |||
16 | ||||
17 | You should have received a copy of the GNU General Public License | |||
18 | along with this program; if not, write to the Free Software | |||
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |||
20 | ||||
21 | #include "bfd.h" | |||
22 | #include "sysdep.h" | |||
23 | #include "libbfd.h" | |||
24 | #include "elf-bfd.h" | |||
25 | #include "elf/dwarf2.h" | |||
26 | ||||
27 | #define EH_FRAME_HDR_SIZE8 8 | |||
28 | ||||
29 | /* Helper function for reading uleb128 encoded data. */ | |||
30 | ||||
31 | static bfd_vma | |||
32 | read_unsigned_leb128 (bfd *abfd ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
33 | char *buf, | |||
34 | unsigned int *bytes_read_ptr) | |||
35 | { | |||
36 | bfd_vma result; | |||
37 | unsigned int num_read; | |||
38 | int shift; | |||
39 | unsigned char byte; | |||
40 | ||||
41 | result = 0; | |||
42 | shift = 0; | |||
43 | num_read = 0; | |||
44 | do | |||
45 | { | |||
46 | byte = bfd_get_8 (abfd, (bfd_byte *) buf)(*(unsigned char *) ((bfd_byte *) buf) & 0xff); | |||
47 | buf++; | |||
48 | num_read++; | |||
49 | result |= (((bfd_vma) byte & 0x7f) << shift); | |||
50 | shift += 7; | |||
51 | } | |||
52 | while (byte & 0x80); | |||
53 | *bytes_read_ptr = num_read; | |||
54 | return result; | |||
55 | } | |||
56 | ||||
57 | /* Helper function for reading sleb128 encoded data. */ | |||
58 | ||||
59 | static bfd_signed_vma | |||
60 | read_signed_leb128 (bfd *abfd ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
61 | char *buf, | |||
62 | unsigned int * bytes_read_ptr) | |||
63 | { | |||
64 | bfd_vma result; | |||
65 | int shift; | |||
66 | int num_read; | |||
67 | unsigned char byte; | |||
68 | ||||
69 | result = 0; | |||
70 | shift = 0; | |||
71 | num_read = 0; | |||
72 | do | |||
73 | { | |||
74 | byte = bfd_get_8 (abfd, (bfd_byte *) buf)(*(unsigned char *) ((bfd_byte *) buf) & 0xff); | |||
75 | buf ++; | |||
76 | num_read ++; | |||
77 | result |= (((bfd_vma) byte & 0x7f) << shift); | |||
78 | shift += 7; | |||
79 | } | |||
80 | while (byte & 0x80); | |||
81 | if (byte & 0x40) | |||
82 | result |= (((bfd_vma) -1) << (shift - 7)) << 7; | |||
83 | *bytes_read_ptr = num_read; | |||
84 | return result; | |||
85 | } | |||
86 | ||||
87 | #define read_uleb128(VAR, BUF)do { (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp ); (BUF) += leb128_tmp; } while (0) \ | |||
88 | do \ | |||
89 | { \ | |||
90 | (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp); \ | |||
91 | (BUF) += leb128_tmp; \ | |||
92 | } \ | |||
93 | while (0) | |||
94 | ||||
95 | #define read_sleb128(VAR, BUF)do { (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); (BUF) += leb128_tmp; } while (0) \ | |||
96 | do \ | |||
97 | { \ | |||
98 | (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); \ | |||
99 | (BUF) += leb128_tmp; \ | |||
100 | } \ | |||
101 | while (0) | |||
102 | ||||
103 | /* Return 0 if either encoding is variable width, or not yet known to bfd. */ | |||
104 | ||||
105 | static | |||
106 | int get_DW_EH_PE_width (int encoding, int ptr_size) | |||
107 | { | |||
108 | /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame | |||
109 | was added to bfd. */ | |||
110 | if ((encoding & 0x60) == 0x60) | |||
111 | return 0; | |||
112 | ||||
113 | switch (encoding & 7) | |||
114 | { | |||
115 | case DW_EH_PE_udata20x02: return 2; | |||
116 | case DW_EH_PE_udata40x03: return 4; | |||
117 | case DW_EH_PE_udata80x04: return 8; | |||
118 | case DW_EH_PE_absptr0x00: return ptr_size; | |||
119 | default: | |||
120 | break; | |||
121 | } | |||
122 | ||||
123 | return 0; | |||
124 | } | |||
125 | ||||
126 | #define get_DW_EH_PE_signed(encoding)(((encoding) & 0x08) != 0) (((encoding) & DW_EH_PE_signed0x08) != 0) | |||
127 | ||||
128 | /* Read a width sized value from memory. */ | |||
129 | ||||
130 | static bfd_vma | |||
131 | read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed) | |||
132 | { | |||
133 | bfd_vma value; | |||
134 | ||||
135 | switch (width) | |||
136 | { | |||
137 | case 2: | |||
138 | if (is_signed) | |||
139 | value = bfd_get_signed_16 (abfd, buf)((*((abfd)->xvec->bfd_getx_signed_16)) (buf)); | |||
140 | else | |||
141 | value = bfd_get_16 (abfd, buf)((*((abfd)->xvec->bfd_getx16)) (buf)); | |||
142 | break; | |||
143 | case 4: | |||
144 | if (is_signed) | |||
145 | value = bfd_get_signed_32 (abfd, buf)((*((abfd)->xvec->bfd_getx_signed_32)) (buf)); | |||
146 | else | |||
147 | value = bfd_get_32 (abfd, buf)((*((abfd)->xvec->bfd_getx32)) (buf)); | |||
148 | break; | |||
149 | case 8: | |||
150 | if (is_signed) | |||
151 | value = bfd_get_signed_64 (abfd, buf)((*((abfd)->xvec->bfd_getx_signed_64)) (buf)); | |||
152 | else | |||
153 | value = bfd_get_64 (abfd, buf)((*((abfd)->xvec->bfd_getx64)) (buf)); | |||
154 | break; | |||
155 | default: | |||
156 | BFD_FAIL (){ bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,156); }; | |||
157 | return 0; | |||
158 | } | |||
159 | ||||
160 | return value; | |||
161 | } | |||
162 | ||||
163 | /* Store a width sized value to memory. */ | |||
164 | ||||
165 | static void | |||
166 | write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width) | |||
167 | { | |||
168 | switch (width) | |||
169 | { | |||
170 | case 2: bfd_put_16 (abfd, value, buf)((*((abfd)->xvec->bfd_putx16)) ((value),(buf))); break; | |||
171 | case 4: bfd_put_32 (abfd, value, buf)((*((abfd)->xvec->bfd_putx32)) ((value),(buf))); break; | |||
172 | case 8: bfd_put_64 (abfd, value, buf)((*((abfd)->xvec->bfd_putx64)) ((value), (buf))); break; | |||
173 | default: BFD_FAIL (){ bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,173); }; | |||
174 | } | |||
175 | } | |||
176 | ||||
177 | /* Return zero if C1 and C2 CIEs can be merged. */ | |||
178 | ||||
179 | static | |||
180 | int cie_compare (struct cie *c1, struct cie *c2) | |||
181 | { | |||
182 | if (c1->hdr.length == c2->hdr.length | |||
183 | && c1->version == c2->version | |||
184 | && strcmp (c1->augmentation, c2->augmentation) == 0 | |||
185 | && strcmp (c1->augmentation, "eh") != 0 | |||
186 | && c1->code_align == c2->code_align | |||
187 | && c1->data_align == c2->data_align | |||
188 | && c1->ra_column == c2->ra_column | |||
189 | && c1->augmentation_size == c2->augmentation_size | |||
190 | && c1->personality == c2->personality | |||
191 | && c1->per_encoding == c2->per_encoding | |||
192 | && c1->lsda_encoding == c2->lsda_encoding | |||
193 | && c1->fde_encoding == c2->fde_encoding | |||
194 | && c1->initial_insn_length == c2->initial_insn_length | |||
195 | && memcmp (c1->initial_instructions, | |||
196 | c2->initial_instructions, | |||
197 | c1->initial_insn_length) == 0) | |||
198 | return 0; | |||
199 | ||||
200 | return 1; | |||
201 | } | |||
202 | ||||
203 | /* This function is called for each input file before the .eh_frame | |||
204 | section is relocated. It discards duplicate CIEs and FDEs for discarded | |||
205 | functions. The function returns TRUE iff any entries have been | |||
206 | deleted. */ | |||
207 | ||||
208 | bfd_boolean | |||
209 | _bfd_elf_discard_section_eh_frame | |||
210 | (bfd *abfd, struct bfd_link_info *info, asection *sec, | |||
211 | bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), | |||
212 | struct elf_reloc_cookie *cookie) | |||
213 | { | |||
214 | bfd_byte *ehbuf = NULL((void*)0), *buf; | |||
215 | bfd_byte *last_cie, *last_fde; | |||
216 | struct cie_header hdr; | |||
217 | struct cie cie; | |||
218 | struct elf_link_hash_table *htab; | |||
219 | struct eh_frame_hdr_info *hdr_info; | |||
220 | struct eh_frame_sec_info *sec_info = NULL((void*)0); | |||
221 | unsigned int leb128_tmp; | |||
222 | unsigned int cie_usage_count, last_cie_ndx, i, offset; | |||
223 | unsigned int make_relative, make_lsda_relative; | |||
224 | bfd_size_type new_size; | |||
225 | unsigned int ptr_size; | |||
226 | ||||
227 | if (sec->_raw_size == 0) | |||
228 | { | |||
229 | /* This file does not contain .eh_frame information. */ | |||
230 | return FALSE0; | |||
231 | } | |||
232 | ||||
233 | if ((sec->output_section != NULL((void*)0) | |||
234 | && bfd_is_abs_section (sec->output_section)((sec->output_section) == ((asection *) &bfd_abs_section )))) | |||
235 | { | |||
236 | /* At least one of the sections is being discarded from the | |||
237 | link, so we should just ignore them. */ | |||
238 | return FALSE0; | |||
239 | } | |||
240 | ||||
241 | htab = elf_hash_table (info)((struct elf_link_hash_table *) ((info)->hash)); | |||
242 | hdr_info = &htab->eh_info; | |||
243 | ||||
244 | /* Read the frame unwind information from abfd. */ | |||
245 | ||||
246 | ehbuf = bfd_malloc (sec->_raw_size); | |||
247 | if (ehbuf == NULL((void*)0)) | |||
248 | goto free_no_table; | |||
249 | ||||
250 | if (! bfd_get_section_contents (abfd, sec, ehbuf, 0, sec->_raw_size)) | |||
251 | goto free_no_table; | |||
252 | ||||
253 | if (sec->_raw_size >= 4 | |||
254 | && bfd_get_32 (abfd, ehbuf)((*((abfd)->xvec->bfd_getx32)) (ehbuf)) == 0 | |||
255 | && cookie->rel == cookie->relend) | |||
256 | { | |||
257 | /* Empty .eh_frame section. */ | |||
258 | free (ehbuf); | |||
259 | return FALSE0; | |||
260 | } | |||
261 | ||||
262 | /* If .eh_frame section size doesn't fit into int, we cannot handle | |||
263 | it (it would need to use 64-bit .eh_frame format anyway). */ | |||
264 | if (sec->_raw_size != (unsigned int) sec->_raw_size) | |||
265 | goto free_no_table; | |||
266 | ||||
267 | ptr_size = (elf_elfheader (abfd)(((abfd) -> tdata.elf_obj_data) -> elf_header)->e_ident[EI_CLASS4] | |||
268 | == ELFCLASS642) ? 8 : 4; | |||
269 | buf = ehbuf; | |||
270 | last_cie = NULL((void*)0); | |||
271 | last_cie_ndx = 0; | |||
272 | memset (&cie, 0, sizeof (cie)); | |||
273 | cie_usage_count = 0; | |||
274 | new_size = sec->_raw_size; | |||
275 | make_relative = hdr_info->last_cie.make_relative; | |||
276 | make_lsda_relative = hdr_info->last_cie.make_lsda_relative; | |||
277 | sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) | |||
278 | + 99 * sizeof (struct eh_cie_fde)); | |||
279 | if (sec_info == NULL((void*)0)) | |||
280 | goto free_no_table; | |||
281 | sec_info->alloced = 100; | |||
282 | ||||
283 | #define ENSURE_NO_RELOCS(buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table \ | |||
284 | if (cookie->rel < cookie->relend \ | |||
285 | && (cookie->rel->r_offset \ | |||
286 | < (bfd_size_type) ((buf) - ehbuf)) \ | |||
287 | && cookie->rel->r_info != 0) \ | |||
288 | goto free_no_table | |||
289 | ||||
290 | #define SKIP_RELOCS(buf)while (cookie->rel < cookie->relend && (cookie ->rel->r_offset < (bfd_size_type) ((buf) - ehbuf))) cookie ->rel++ \ | |||
291 | while (cookie->rel < cookie->relend \ | |||
292 | && (cookie->rel->r_offset \ | |||
293 | < (bfd_size_type) ((buf) - ehbuf))) \ | |||
294 | cookie->rel++ | |||
295 | ||||
296 | #define GET_RELOC(buf)((cookie->rel < cookie->relend && (cookie-> rel->r_offset == (bfd_size_type) ((buf) - ehbuf))) ? cookie ->rel : ((void*)0)) \ | |||
297 | ((cookie->rel < cookie->relend \ | |||
298 | && (cookie->rel->r_offset \ | |||
299 | == (bfd_size_type) ((buf) - ehbuf))) \ | |||
300 | ? cookie->rel : NULL((void*)0)) | |||
301 | ||||
302 | for (;;) | |||
303 | { | |||
304 | unsigned char *aug; | |||
305 | ||||
306 | if (sec_info->count == sec_info->alloced) | |||
307 | { | |||
308 | sec_info = bfd_realloc (sec_info, | |||
309 | sizeof (struct eh_frame_sec_info) | |||
310 | + (sec_info->alloced + 99) | |||
311 | * sizeof (struct eh_cie_fde)); | |||
312 | if (sec_info == NULL((void*)0)) | |||
313 | goto free_no_table; | |||
314 | ||||
315 | memset (&sec_info->entry[sec_info->alloced], 0, | |||
316 | 100 * sizeof (struct eh_cie_fde)); | |||
317 | sec_info->alloced += 100; | |||
318 | } | |||
319 | ||||
320 | last_fde = buf; | |||
321 | /* If we are at the end of the section, we still need to decide | |||
322 | on whether to output or discard last encountered CIE (if any). */ | |||
323 | if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size) | |||
324 | hdr.id = (unsigned int) -1; | |||
325 | else | |||
326 | { | |||
327 | if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) | |||
328 | /* No space for CIE/FDE header length. */ | |||
329 | goto free_no_table; | |||
330 | ||||
331 | hdr.length = bfd_get_32 (abfd, buf)((*((abfd)->xvec->bfd_getx32)) (buf)); | |||
332 | if (hdr.length == 0xffffffff) | |||
333 | /* 64-bit .eh_frame is not supported. */ | |||
334 | goto free_no_table; | |||
335 | buf += 4; | |||
336 | if ((bfd_size_type) (buf - ehbuf) + hdr.length > sec->_raw_size) | |||
337 | /* CIE/FDE not contained fully in this .eh_frame input section. */ | |||
338 | goto free_no_table; | |||
339 | ||||
340 | sec_info->entry[sec_info->count].offset = last_fde - ehbuf; | |||
341 | sec_info->entry[sec_info->count].size = 4 + hdr.length; | |||
342 | ||||
343 | if (hdr.length == 0) | |||
344 | { | |||
345 | /* CIE with length 0 must be only the last in the section. */ | |||
346 | if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) | |||
347 | goto free_no_table; | |||
348 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
349 | sec_info->count++; | |||
350 | /* Now just finish last encountered CIE processing and break | |||
351 | the loop. */ | |||
352 | hdr.id = (unsigned int) -1; | |||
353 | } | |||
354 | else | |||
355 | { | |||
356 | hdr.id = bfd_get_32 (abfd, buf)((*((abfd)->xvec->bfd_getx32)) (buf)); | |||
357 | buf += 4; | |||
358 | if (hdr.id == (unsigned int) -1) | |||
359 | goto free_no_table; | |||
360 | } | |||
361 | } | |||
362 | ||||
363 | if (hdr.id == 0 || hdr.id == (unsigned int) -1) | |||
364 | { | |||
365 | unsigned int initial_insn_length; | |||
366 | ||||
367 | /* CIE */ | |||
368 | if (last_cie != NULL((void*)0)) | |||
369 | { | |||
370 | /* Now check if this CIE is identical to the last CIE, | |||
371 | in which case we can remove it provided we adjust | |||
372 | all FDEs. Also, it can be removed if we have removed | |||
373 | all FDEs using it. */ | |||
374 | if ((!info->relocatable | |||
375 | && hdr_info->last_cie_sec | |||
376 | && (sec->output_section | |||
377 | == hdr_info->last_cie_sec->output_section) | |||
378 | && cie_compare (&cie, &hdr_info->last_cie) == 0) | |||
379 | || cie_usage_count == 0) | |||
380 | { | |||
381 | new_size -= cie.hdr.length + 4; | |||
382 | sec_info->entry[last_cie_ndx].removed = 1; | |||
383 | sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; | |||
384 | sec_info->entry[last_cie_ndx].new_offset | |||
385 | = hdr_info->last_cie_offset; | |||
386 | } | |||
387 | else | |||
388 | { | |||
389 | hdr_info->last_cie = cie; | |||
390 | hdr_info->last_cie_sec = sec; | |||
391 | hdr_info->last_cie_offset = last_cie - ehbuf; | |||
392 | sec_info->entry[last_cie_ndx].make_relative | |||
393 | = cie.make_relative; | |||
394 | sec_info->entry[last_cie_ndx].make_lsda_relative | |||
395 | = cie.make_lsda_relative; | |||
396 | sec_info->entry[last_cie_ndx].per_encoding_relative | |||
397 | = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel0x10; | |||
398 | } | |||
399 | } | |||
400 | ||||
401 | if (hdr.id == (unsigned int) -1) | |||
402 | break; | |||
403 | ||||
404 | last_cie_ndx = sec_info->count; | |||
405 | sec_info->entry[sec_info->count].cie = 1; | |||
406 | ||||
407 | cie_usage_count = 0; | |||
408 | memset (&cie, 0, sizeof (cie)); | |||
409 | cie.hdr = hdr; | |||
410 | cie.version = *buf++; | |||
411 | ||||
412 | /* Cannot handle unknown versions. */ | |||
413 | if (cie.version != 1) | |||
414 | goto free_no_table; | |||
415 | if (strlen (buf) > sizeof (cie.augmentation) - 1) | |||
416 | goto free_no_table; | |||
417 | ||||
418 | strcpy (cie.augmentation, buf); | |||
419 | buf = strchr (buf, '\0') + 1; | |||
420 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
421 | if (buf[0] == 'e' && buf[1] == 'h') | |||
422 | { | |||
423 | /* GCC < 3.0 .eh_frame CIE */ | |||
424 | /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ | |||
425 | is private to each CIE, so we don't need it for anything. | |||
426 | Just skip it. */ | |||
427 | buf += ptr_size; | |||
428 | SKIP_RELOCS (buf)while (cookie->rel < cookie->relend && (cookie ->rel->r_offset < (bfd_size_type) ((buf) - ehbuf))) cookie ->rel++; | |||
429 | } | |||
430 | read_uleb128 (cie.code_align, buf)do { (cie.code_align) = read_unsigned_leb128 (abfd, buf, & leb128_tmp); (buf) += leb128_tmp; } while (0); | |||
431 | read_sleb128 (cie.data_align, buf)do { (cie.data_align) = read_signed_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
432 | /* Note - in DWARF2 the return address column is an unsigned byte. | |||
433 | In DWARF3 it is a ULEB128. We are following DWARF3. For most | |||
434 | ports this will not matter as the value will be less than 128. | |||
435 | For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC | |||
436 | which conforms to the DWARF3 standard. */ | |||
437 | read_uleb128 (cie.ra_column, buf)do { (cie.ra_column) = read_unsigned_leb128 (abfd, buf, & leb128_tmp); (buf) += leb128_tmp; } while (0); | |||
438 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
439 | cie.lsda_encoding = DW_EH_PE_omit0xff; | |||
440 | cie.fde_encoding = DW_EH_PE_omit0xff; | |||
441 | cie.per_encoding = DW_EH_PE_omit0xff; | |||
442 | aug = cie.augmentation; | |||
443 | if (aug[0] != 'e' || aug[1] != 'h') | |||
444 | { | |||
445 | if (*aug == 'z') | |||
446 | { | |||
447 | aug++; | |||
448 | read_uleb128 (cie.augmentation_size, buf)do { (cie.augmentation_size) = read_unsigned_leb128 (abfd, buf , &leb128_tmp); (buf) += leb128_tmp; } while (0); | |||
449 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
450 | } | |||
451 | ||||
452 | while (*aug != '\0') | |||
453 | switch (*aug++) | |||
454 | { | |||
455 | case 'L': | |||
456 | cie.lsda_encoding = *buf++; | |||
457 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
458 | if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) | |||
459 | goto free_no_table; | |||
460 | break; | |||
461 | case 'R': | |||
462 | cie.fde_encoding = *buf++; | |||
463 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
464 | if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) | |||
465 | goto free_no_table; | |||
466 | break; | |||
467 | case 'P': | |||
468 | { | |||
469 | int per_width; | |||
470 | ||||
471 | cie.per_encoding = *buf++; | |||
472 | per_width = get_DW_EH_PE_width (cie.per_encoding, | |||
473 | ptr_size); | |||
474 | if (per_width == 0) | |||
475 | goto free_no_table; | |||
476 | if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned0x50) | |||
477 | buf = (ehbuf | |||
478 | + ((buf - ehbuf + per_width - 1) | |||
479 | & ~((bfd_size_type) per_width - 1))); | |||
480 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
481 | /* Ensure we have a reloc here, against | |||
482 | a global symbol. */ | |||
483 | if (GET_RELOC (buf)((cookie->rel < cookie->relend && (cookie-> rel->r_offset == (bfd_size_type) ((buf) - ehbuf))) ? cookie ->rel : ((void*)0)) != NULL((void*)0)) | |||
484 | { | |||
485 | unsigned long r_symndx; | |||
486 | ||||
487 | #ifdef BFD64 | |||
488 | if (ptr_size == 8) | |||
489 | r_symndx = ELF64_R_SYM (cookie->rel->r_info)((cookie->rel->r_info) >> 32); | |||
490 | else | |||
491 | #endif | |||
492 | r_symndx = ELF32_R_SYM (cookie->rel->r_info)((cookie->rel->r_info) >> 8); | |||
493 | if (r_symndx >= cookie->locsymcount) | |||
494 | { | |||
495 | struct elf_link_hash_entry *h; | |||
496 | ||||
497 | r_symndx -= cookie->extsymoff; | |||
498 | h = cookie->sym_hashes[r_symndx]; | |||
499 | ||||
500 | while (h->root.type == bfd_link_hash_indirect | |||
501 | || h->root.type == bfd_link_hash_warning) | |||
502 | h = (struct elf_link_hash_entry *) | |||
503 | h->root.u.i.link; | |||
504 | ||||
505 | cie.personality = h; | |||
506 | } | |||
507 | cookie->rel++; | |||
508 | } | |||
509 | buf += per_width; | |||
510 | } | |||
511 | break; | |||
512 | default: | |||
513 | /* Unrecognized augmentation. Better bail out. */ | |||
514 | goto free_no_table; | |||
515 | } | |||
516 | } | |||
517 | ||||
518 | /* For shared libraries, try to get rid of as many RELATIVE relocs | |||
519 | as possible. */ | |||
520 | if (info->shared | |||
521 | && (get_elf_backend_data (abfd)((const struct elf_backend_data *) (abfd)->xvec->backend_data ) | |||
522 | ->elf_backend_can_make_relative_eh_frame | |||
523 | (abfd, info, sec)) | |||
524 | && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr0x00) | |||
525 | cie.make_relative = 1; | |||
526 | ||||
527 | if (info->shared | |||
528 | && (get_elf_backend_data (abfd)((const struct elf_backend_data *) (abfd)->xvec->backend_data ) | |||
529 | ->elf_backend_can_make_lsda_relative_eh_frame | |||
530 | (abfd, info, sec)) | |||
531 | && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr0x00) | |||
532 | cie.make_lsda_relative = 1; | |||
533 | ||||
534 | /* If FDE encoding was not specified, it defaults to | |||
535 | DW_EH_absptr. */ | |||
536 | if (cie.fde_encoding == DW_EH_PE_omit0xff) | |||
537 | cie.fde_encoding = DW_EH_PE_absptr0x00; | |||
538 | ||||
539 | initial_insn_length = cie.hdr.length - (buf - last_fde - 4); | |||
540 | if (initial_insn_length <= 50) | |||
541 | { | |||
542 | cie.initial_insn_length = initial_insn_length; | |||
543 | memcpy (cie.initial_instructions, buf, initial_insn_length); | |||
544 | } | |||
545 | buf += initial_insn_length; | |||
546 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
547 | last_cie = last_fde; | |||
548 | } | |||
549 | else | |||
550 | { | |||
551 | /* Ensure this FDE uses the last CIE encountered. */ | |||
552 | if (last_cie == NULL((void*)0) | |||
553 | || hdr.id != (unsigned int) (buf - 4 - last_cie)) | |||
554 | goto free_no_table; | |||
555 | ||||
556 | ENSURE_NO_RELOCS (buf)if (cookie->rel < cookie->relend && (cookie-> rel->r_offset < (bfd_size_type) ((buf) - ehbuf)) && cookie->rel->r_info != 0) goto free_no_table; | |||
557 | if (GET_RELOC (buf)((cookie->rel < cookie->relend && (cookie-> rel->r_offset == (bfd_size_type) ((buf) - ehbuf))) ? cookie ->rel : ((void*)0)) == NULL((void*)0)) | |||
558 | /* This should not happen. */ | |||
559 | goto free_no_table; | |||
560 | if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) | |||
561 | { | |||
562 | /* This is a FDE against a discarded section. It should | |||
563 | be deleted. */ | |||
564 | new_size -= hdr.length + 4; | |||
565 | sec_info->entry[sec_info->count].removed = 1; | |||
566 | } | |||
567 | else | |||
568 | { | |||
569 | if (info->shared | |||
570 | && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr0x00 | |||
571 | && cie.make_relative == 0) | |||
572 | || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned0x50)) | |||
573 | { | |||
574 | /* If a shared library uses absolute pointers | |||
575 | which we cannot turn into PC relative, | |||
576 | don't create the binary search table, | |||
577 | since it is affected by runtime relocations. */ | |||
578 | hdr_info->table = FALSE0; | |||
579 | } | |||
580 | cie_usage_count++; | |||
581 | hdr_info->fde_count++; | |||
582 | } | |||
583 | if (cie.lsda_encoding != DW_EH_PE_omit0xff) | |||
584 | { | |||
585 | unsigned int dummy; | |||
586 | ||||
587 | aug = buf; | |||
588 | buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); | |||
589 | if (cie.augmentation[0] == 'z') | |||
590 | read_uleb128 (dummy, buf)do { (dummy) = read_unsigned_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
591 | /* If some new augmentation data is added before LSDA | |||
592 | in FDE augmentation area, this need to be adjusted. */ | |||
593 | sec_info->entry[sec_info->count].lsda_offset = (buf - aug); | |||
594 | } | |||
595 | buf = last_fde + 4 + hdr.length; | |||
596 | SKIP_RELOCS (buf)while (cookie->rel < cookie->relend && (cookie ->rel->r_offset < (bfd_size_type) ((buf) - ehbuf))) cookie ->rel++; | |||
597 | } | |||
598 | ||||
599 | sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; | |||
600 | sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; | |||
601 | sec_info->count++; | |||
602 | } | |||
603 | ||||
604 | elf_section_data (sec)((struct bfd_elf_section_data*)sec->used_by_bfd)->sec_info = sec_info; | |||
605 | sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME3; | |||
606 | ||||
607 | /* Ok, now we can assign new offsets. */ | |||
608 | offset = 0; | |||
609 | last_cie_ndx = 0; | |||
610 | for (i = 0; i < sec_info->count; i++) | |||
611 | { | |||
612 | if (! sec_info->entry[i].removed) | |||
613 | { | |||
614 | sec_info->entry[i].new_offset = offset; | |||
615 | offset += sec_info->entry[i].size; | |||
616 | if (sec_info->entry[i].cie) | |||
617 | { | |||
618 | last_cie_ndx = i; | |||
619 | make_relative = sec_info->entry[i].make_relative; | |||
620 | make_lsda_relative = sec_info->entry[i].make_lsda_relative; | |||
621 | } | |||
622 | else | |||
623 | { | |||
624 | sec_info->entry[i].make_relative = make_relative; | |||
625 | sec_info->entry[i].make_lsda_relative = make_lsda_relative; | |||
626 | sec_info->entry[i].per_encoding_relative = 0; | |||
627 | } | |||
628 | } | |||
629 | else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) | |||
630 | { | |||
631 | /* Need to adjust new_offset too. */ | |||
632 | BFD_ASSERT (sec_info->entry[last_cie_ndx].offset{ if (!(sec_info->entry[last_cie_ndx].offset == sec_info-> entry[i].new_offset)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,633); } | |||
633 | == sec_info->entry[i].new_offset){ if (!(sec_info->entry[last_cie_ndx].offset == sec_info-> entry[i].new_offset)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,633); }; | |||
634 | sec_info->entry[i].new_offset | |||
635 | = sec_info->entry[last_cie_ndx].new_offset; | |||
636 | } | |||
637 | } | |||
638 | if (hdr_info->last_cie_sec == sec) | |||
639 | { | |||
640 | BFD_ASSERT (sec_info->entry[last_cie_ndx].offset{ if (!(sec_info->entry[last_cie_ndx].offset == hdr_info-> last_cie_offset)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,641); } | |||
641 | == hdr_info->last_cie_offset){ if (!(sec_info->entry[last_cie_ndx].offset == hdr_info-> last_cie_offset)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,641); }; | |||
642 | hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; | |||
643 | } | |||
644 | ||||
645 | /* FIXME: Currently it is not possible to shrink sections to zero size at | |||
646 | this point, so build a fake minimal CIE. */ | |||
647 | if (new_size == 0) | |||
648 | new_size = 16; | |||
649 | ||||
650 | /* Shrink the sec as needed. */ | |||
651 | sec->_cooked_size = new_size; | |||
652 | if (sec->_cooked_size == 0) | |||
653 | sec->flags |= SEC_EXCLUDE0x40000; | |||
654 | ||||
655 | free (ehbuf); | |||
656 | return new_size != sec->_raw_size; | |||
657 | ||||
658 | free_no_table: | |||
659 | if (ehbuf) | |||
660 | free (ehbuf); | |||
661 | if (sec_info) | |||
662 | free (sec_info); | |||
663 | hdr_info->table = FALSE0; | |||
664 | hdr_info->last_cie.hdr.length = 0; | |||
665 | return FALSE0; | |||
666 | } | |||
667 | ||||
668 | /* This function is called for .eh_frame_hdr section after | |||
669 | _bfd_elf_discard_section_eh_frame has been called on all .eh_frame | |||
670 | input sections. It finalizes the size of .eh_frame_hdr section. */ | |||
671 | ||||
672 | bfd_boolean | |||
673 | _bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) | |||
674 | { | |||
675 | struct elf_link_hash_table *htab; | |||
676 | struct eh_frame_hdr_info *hdr_info; | |||
677 | asection *sec; | |||
678 | ||||
679 | htab = elf_hash_table (info)((struct elf_link_hash_table *) ((info)->hash)); | |||
680 | hdr_info = &htab->eh_info; | |||
681 | sec = hdr_info->hdr_sec; | |||
682 | if (sec == NULL((void*)0)) | |||
683 | return FALSE0; | |||
684 | ||||
685 | sec->_cooked_size = EH_FRAME_HDR_SIZE8; | |||
686 | if (hdr_info->table) | |||
687 | sec->_cooked_size += 4 + hdr_info->fde_count * 8; | |||
688 | ||||
689 | /* Request program headers to be recalculated. */ | |||
690 | elf_tdata (abfd)((abfd) -> tdata.elf_obj_data)->program_header_size = 0; | |||
691 | elf_tdata (abfd)((abfd) -> tdata.elf_obj_data)->eh_frame_hdr = sec; | |||
692 | return TRUE1; | |||
693 | } | |||
694 | ||||
695 | /* This function is called from size_dynamic_sections. | |||
696 | It needs to decide whether .eh_frame_hdr should be output or not, | |||
697 | because later on it is too late for calling _bfd_strip_section_from_output, | |||
698 | since dynamic symbol table has been sized. */ | |||
699 | ||||
700 | bfd_boolean | |||
701 | _bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) | |||
702 | { | |||
703 | asection *o; | |||
704 | bfd *abfd; | |||
705 | struct elf_link_hash_table *htab; | |||
706 | struct eh_frame_hdr_info *hdr_info; | |||
707 | ||||
708 | htab = elf_hash_table (info)((struct elf_link_hash_table *) ((info)->hash)); | |||
709 | hdr_info = &htab->eh_info; | |||
710 | if (hdr_info->hdr_sec == NULL((void*)0)) | |||
711 | return TRUE1; | |||
712 | ||||
713 | if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)((hdr_info->hdr_sec->output_section) == ((asection *) & bfd_abs_section))) | |||
714 | { | |||
715 | hdr_info->hdr_sec = NULL((void*)0); | |||
716 | return TRUE1; | |||
717 | } | |||
718 | ||||
719 | abfd = NULL((void*)0); | |||
720 | if (info->eh_frame_hdr) | |||
721 | for (abfd = info->input_bfds; abfd != NULL((void*)0); abfd = abfd->link_next) | |||
722 | { | |||
723 | /* Count only sections which have at least a single CIE or FDE. | |||
724 | There cannot be any CIE or FDE <= 8 bytes. */ | |||
725 | o = bfd_get_section_by_name (abfd, ".eh_frame"); | |||
726 | if (o && o->_raw_size > 8 && !bfd_is_abs_section (o->output_section)((o->output_section) == ((asection *) &bfd_abs_section ))) | |||
727 | break; | |||
728 | } | |||
729 | ||||
730 | if (abfd == NULL((void*)0)) | |||
731 | { | |||
732 | _bfd_strip_section_from_output (info, hdr_info->hdr_sec); | |||
733 | hdr_info->hdr_sec = NULL((void*)0); | |||
734 | return TRUE1; | |||
735 | } | |||
736 | ||||
737 | hdr_info->table = TRUE1; | |||
738 | return TRUE1; | |||
739 | } | |||
740 | ||||
741 | /* Adjust an address in the .eh_frame section. Given OFFSET within | |||
742 | SEC, this returns the new offset in the adjusted .eh_frame section, | |||
743 | or -1 if the address refers to a CIE/FDE which has been removed | |||
744 | or to offset with dynamic relocation which is no longer needed. */ | |||
745 | ||||
746 | bfd_vma | |||
747 | _bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
748 | asection *sec, | |||
749 | bfd_vma offset) | |||
750 | { | |||
751 | struct eh_frame_sec_info *sec_info; | |||
752 | unsigned int lo, hi, mid; | |||
753 | ||||
754 | if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME3) | |||
755 | return offset; | |||
756 | sec_info = elf_section_data (sec)((struct bfd_elf_section_data*)sec->used_by_bfd)->sec_info; | |||
757 | ||||
758 | if (offset >= sec->_raw_size) | |||
759 | return offset - (sec->_cooked_size - sec->_raw_size); | |||
760 | ||||
761 | lo = 0; | |||
762 | hi = sec_info->count; | |||
763 | mid = 0; | |||
764 | while (lo < hi) | |||
765 | { | |||
766 | mid = (lo + hi) / 2; | |||
767 | if (offset < sec_info->entry[mid].offset) | |||
768 | hi = mid; | |||
769 | else if (offset | |||
770 | >= sec_info->entry[mid].offset + sec_info->entry[mid].size) | |||
771 | lo = mid + 1; | |||
772 | else | |||
773 | break; | |||
774 | } | |||
775 | ||||
776 | BFD_ASSERT (lo < hi){ if (!(lo < hi)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,776); }; | |||
777 | ||||
778 | /* FDE or CIE was removed. */ | |||
779 | if (sec_info->entry[mid].removed) | |||
780 | return (bfd_vma) -1; | |||
781 | ||||
782 | /* If converting to DW_EH_PE_pcrel, there will be no need for run-time | |||
783 | relocation against FDE's initial_location field. */ | |||
784 | if (sec_info->entry[mid].make_relative | |||
785 | && ! sec_info->entry[mid].cie | |||
786 | && offset == sec_info->entry[mid].offset + 8) | |||
787 | return (bfd_vma) -2; | |||
788 | ||||
789 | /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need | |||
790 | for run-time relocation against LSDA field. */ | |||
791 | if (sec_info->entry[mid].make_lsda_relative | |||
792 | && ! sec_info->entry[mid].cie | |||
793 | && (offset == (sec_info->entry[mid].offset + 8 | |||
794 | + sec_info->entry[mid].lsda_offset))) | |||
795 | return (bfd_vma) -2; | |||
796 | ||||
797 | return (offset + sec_info->entry[mid].new_offset | |||
798 | - sec_info->entry[mid].offset); | |||
799 | } | |||
800 | ||||
801 | /* Write out .eh_frame section. This is called with the relocated | |||
802 | contents. */ | |||
803 | ||||
804 | bfd_boolean | |||
805 | _bfd_elf_write_section_eh_frame (bfd *abfd, | |||
806 | struct bfd_link_info *info, | |||
807 | asection *sec, | |||
808 | bfd_byte *contents) | |||
809 | { | |||
810 | struct eh_frame_sec_info *sec_info; | |||
811 | struct elf_link_hash_table *htab; | |||
812 | struct eh_frame_hdr_info *hdr_info; | |||
813 | unsigned int i; | |||
814 | bfd_byte *p, *buf; | |||
815 | unsigned int leb128_tmp; | |||
816 | unsigned int cie_offset = 0; | |||
817 | unsigned int ptr_size; | |||
818 | ||||
819 | ptr_size = (elf_elfheader (sec->owner)(((sec->owner) -> tdata.elf_obj_data) -> elf_header)->e_ident[EI_CLASS4] | |||
820 | == ELFCLASS642) ? 8 : 4; | |||
821 | ||||
822 | if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME3) | |||
823 | return bfd_set_section_contents (abfd, sec->output_section, contents, | |||
824 | sec->output_offset, sec->_raw_size); | |||
825 | sec_info = elf_section_data (sec)((struct bfd_elf_section_data*)sec->used_by_bfd)->sec_info; | |||
826 | htab = elf_hash_table (info)((struct elf_link_hash_table *) ((info)->hash)); | |||
827 | hdr_info = &htab->eh_info; | |||
828 | if (hdr_info->table && hdr_info->array == NULL((void*)0)) | |||
829 | hdr_info->array | |||
830 | = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); | |||
831 | if (hdr_info->array == NULL((void*)0)) | |||
832 | hdr_info = NULL((void*)0); | |||
833 | ||||
834 | p = contents; | |||
835 | for (i = 0; i < sec_info->count; ++i) | |||
836 | { | |||
837 | if (sec_info->entry[i].removed) | |||
838 | { | |||
839 | if (sec_info->entry[i].cie) | |||
840 | { | |||
841 | /* If CIE is removed due to no remaining FDEs referencing it | |||
842 | and there were no CIEs kept before it, sec_info->entry[i].sec | |||
843 | will be zero. */ | |||
844 | if (sec_info->entry[i].sec == NULL((void*)0)) | |||
845 | cie_offset = 0; | |||
846 | else | |||
847 | { | |||
848 | cie_offset = sec_info->entry[i].new_offset; | |||
849 | cie_offset += (sec_info->entry[i].sec->output_section->vma | |||
850 | + sec_info->entry[i].sec->output_offset | |||
851 | - sec->output_section->vma | |||
852 | - sec->output_offset); | |||
853 | } | |||
854 | } | |||
855 | continue; | |||
856 | } | |||
857 | ||||
858 | if (sec_info->entry[i].cie) | |||
859 | { | |||
860 | /* CIE */ | |||
861 | cie_offset = sec_info->entry[i].new_offset; | |||
862 | if (sec_info->entry[i].make_relative | |||
863 | || sec_info->entry[i].make_lsda_relative | |||
864 | || sec_info->entry[i].per_encoding_relative) | |||
865 | { | |||
866 | unsigned char *aug; | |||
867 | unsigned int action; | |||
868 | unsigned int dummy, per_width, per_encoding; | |||
869 | ||||
870 | /* Need to find 'R' or 'L' augmentation's argument and modify | |||
871 | DW_EH_PE_* value. */ | |||
872 | action = (sec_info->entry[i].make_relative ? 1 : 0) | |||
873 | | (sec_info->entry[i].make_lsda_relative ? 2 : 0) | |||
874 | | (sec_info->entry[i].per_encoding_relative ? 4 : 0); | |||
875 | buf = contents + sec_info->entry[i].offset; | |||
876 | /* Skip length, id and version. */ | |||
877 | buf += 9; | |||
878 | aug = buf; | |||
879 | buf = strchr (buf, '\0') + 1; | |||
880 | read_uleb128 (dummy, buf)do { (dummy) = read_unsigned_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
881 | read_sleb128 (dummy, buf)do { (dummy) = read_signed_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
882 | read_uleb128 (dummy, buf)do { (dummy) = read_unsigned_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
883 | if (*aug == 'z') | |||
884 | { | |||
885 | read_uleb128 (dummy, buf)do { (dummy) = read_unsigned_leb128 (abfd, buf, &leb128_tmp ); (buf) += leb128_tmp; } while (0); | |||
886 | aug++; | |||
887 | } | |||
888 | ||||
889 | while (action) | |||
890 | switch (*aug++) | |||
891 | { | |||
892 | case 'L': | |||
893 | if (action & 2) | |||
894 | { | |||
895 | BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding){ if (!(*buf == sec_info->entry[i].lsda_encoding)) bfd_assert ("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c",895); }; | |||
896 | *buf |= DW_EH_PE_pcrel0x10; | |||
897 | action &= ~2; | |||
898 | } | |||
899 | buf++; | |||
900 | break; | |||
901 | case 'P': | |||
902 | per_encoding = *buf++; | |||
903 | per_width = get_DW_EH_PE_width (per_encoding, | |||
904 | ptr_size); | |||
905 | BFD_ASSERT (per_width != 0){ if (!(per_width != 0)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,905); }; | |||
906 | BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel){ if (!(((per_encoding & 0x70) == 0x10) == sec_info->entry [i].per_encoding_relative)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,907); } | |||
907 | == sec_info->entry[i].per_encoding_relative){ if (!(((per_encoding & 0x70) == 0x10) == sec_info->entry [i].per_encoding_relative)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,907); }; | |||
908 | if ((per_encoding & 0xf0) == DW_EH_PE_aligned0x50) | |||
909 | buf = (contents | |||
910 | + ((buf - contents + per_width - 1) | |||
911 | & ~((bfd_size_type) per_width - 1))); | |||
912 | if (action & 4) | |||
913 | { | |||
914 | bfd_vma value; | |||
915 | ||||
916 | value = read_value (abfd, buf, per_width, | |||
917 | get_DW_EH_PE_signed(((per_encoding) & 0x08) != 0) | |||
918 | (per_encoding)(((per_encoding) & 0x08) != 0)); | |||
919 | value += (sec_info->entry[i].offset | |||
920 | - sec_info->entry[i].new_offset); | |||
921 | write_value (abfd, buf, value, per_width); | |||
922 | action &= ~4; | |||
923 | } | |||
924 | buf += per_width; | |||
925 | break; | |||
926 | case 'R': | |||
927 | if (action & 1) | |||
928 | { | |||
929 | BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding){ if (!(*buf == sec_info->entry[i].fde_encoding)) bfd_assert ("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c",929); }; | |||
930 | *buf |= DW_EH_PE_pcrel0x10; | |||
931 | action &= ~1; | |||
932 | } | |||
933 | buf++; | |||
934 | break; | |||
935 | default: | |||
936 | BFD_FAIL (){ bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,936); }; | |||
937 | } | |||
938 | } | |||
939 | } | |||
940 | else if (sec_info->entry[i].size > 4) | |||
941 | { | |||
942 | /* FDE */ | |||
943 | bfd_vma value = 0, address; | |||
944 | unsigned int width; | |||
945 | ||||
946 | buf = contents + sec_info->entry[i].offset; | |||
947 | /* Skip length. */ | |||
948 | buf += 4; | |||
949 | bfd_put_32 (abfd,((*((abfd)->xvec->bfd_putx32)) ((sec_info->entry[i]. new_offset + 4 - cie_offset),(buf))) | |||
950 | sec_info->entry[i].new_offset + 4 - cie_offset, buf)((*((abfd)->xvec->bfd_putx32)) ((sec_info->entry[i]. new_offset + 4 - cie_offset),(buf))); | |||
951 | buf += 4; | |||
952 | width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, | |||
953 | ptr_size); | |||
954 | address = value = read_value (abfd, buf, width, | |||
955 | get_DW_EH_PE_signed(((sec_info->entry[i].fde_encoding) & 0x08) != 0) | |||
956 | (sec_info->entry[i].fde_encoding)(((sec_info->entry[i].fde_encoding) & 0x08) != 0)); | |||
957 | if (value) | |||
958 | { | |||
959 | switch (sec_info->entry[i].fde_encoding & 0xf0) | |||
960 | { | |||
961 | case DW_EH_PE_indirect0x80: | |||
962 | case DW_EH_PE_textrel0x20: | |||
963 | BFD_ASSERT (hdr_info == NULL){ if (!(hdr_info == ((void*)0))) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,963); }; | |||
964 | break; | |||
965 | case DW_EH_PE_datarel0x30: | |||
966 | { | |||
967 | asection *got = bfd_get_section_by_name (abfd, ".got"); | |||
968 | ||||
969 | BFD_ASSERT (got != NULL){ if (!(got != ((void*)0))) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,969); }; | |||
970 | address += got->vma; | |||
971 | } | |||
972 | break; | |||
973 | case DW_EH_PE_pcrel0x10: | |||
974 | value += (sec_info->entry[i].offset | |||
975 | - sec_info->entry[i].new_offset); | |||
976 | address += (sec->output_section->vma + sec->output_offset | |||
977 | + sec_info->entry[i].offset + 8); | |||
978 | break; | |||
979 | } | |||
980 | if (sec_info->entry[i].make_relative) | |||
981 | value -= (sec->output_section->vma + sec->output_offset | |||
982 | + sec_info->entry[i].new_offset + 8); | |||
983 | write_value (abfd, buf, value, width); | |||
984 | } | |||
985 | ||||
986 | if (hdr_info) | |||
987 | { | |||
988 | hdr_info->array[hdr_info->array_count].initial_loc = address; | |||
989 | hdr_info->array[hdr_info->array_count++].fde | |||
990 | = (sec->output_section->vma + sec->output_offset | |||
991 | + sec_info->entry[i].new_offset); | |||
992 | } | |||
993 | ||||
994 | if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel0x10 | |||
995 | || sec_info->entry[i].make_lsda_relative) | |||
996 | { | |||
997 | buf += sec_info->entry[i].lsda_offset; | |||
998 | width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding, | |||
999 | ptr_size); | |||
1000 | value = read_value (abfd, buf, width, | |||
1001 | get_DW_EH_PE_signed(((sec_info->entry[i].lsda_encoding) & 0x08) != 0) | |||
1002 | (sec_info->entry[i].lsda_encoding)(((sec_info->entry[i].lsda_encoding) & 0x08) != 0)); | |||
1003 | if (value) | |||
1004 | { | |||
1005 | if ((sec_info->entry[i].lsda_encoding & 0xf0) | |||
1006 | == DW_EH_PE_pcrel0x10) | |||
1007 | value += (sec_info->entry[i].offset | |||
1008 | - sec_info->entry[i].new_offset); | |||
1009 | else if (sec_info->entry[i].make_lsda_relative) | |||
1010 | value -= (sec->output_section->vma + sec->output_offset | |||
1011 | + sec_info->entry[i].new_offset + 8 | |||
1012 | + sec_info->entry[i].lsda_offset); | |||
1013 | write_value (abfd, buf, value, width); | |||
1014 | } | |||
1015 | } | |||
1016 | } | |||
1017 | else | |||
1018 | /* Terminating FDE must be at the end of .eh_frame section only. */ | |||
1019 | BFD_ASSERT (i == sec_info->count - 1){ if (!(i == sec_info->count - 1)) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,1019); }; | |||
1020 | ||||
1021 | BFD_ASSERT (p == contents + sec_info->entry[i].new_offset){ if (!(p == contents + sec_info->entry[i].new_offset)) bfd_assert ("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c",1021); }; | |||
1022 | memmove (p, contents + sec_info->entry[i].offset, | |||
1023 | sec_info->entry[i].size); | |||
1024 | p += sec_info->entry[i].size; | |||
1025 | } | |||
1026 | ||||
1027 | /* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to | |||
1028 | shrink sections to zero size, this won't be needed any more. */ | |||
1029 | if (p == contents && sec->_cooked_size == 16) | |||
1030 | { | |||
1031 | bfd_put_32 (abfd, 12, p)((*((abfd)->xvec->bfd_putx32)) ((12),(p))); /* Fake CIE length */ | |||
1032 | bfd_put_32 (abfd, 0, p + 4)((*((abfd)->xvec->bfd_putx32)) ((0),(p + 4))); /* Fake CIE id */ | |||
1033 | p[8] = 1; /* Fake CIE version */ | |||
1034 | memset (p + 9, 0, 7); /* Fake CIE augmentation, 3xleb128 | |||
1035 | and 3xDW_CFA_nop as pad */ | |||
1036 | p += 16; | |||
1037 | } | |||
1038 | else | |||
1039 | { | |||
1040 | unsigned int alignment = 1 << sec->alignment_power; | |||
1041 | unsigned int pad = sec->_cooked_size % alignment; | |||
1042 | ||||
1043 | /* Don't pad beyond the raw size of the output section. It | |||
1044 | can happen at the last input section. */ | |||
1045 | if (pad | |||
1046 | && ((sec->output_offset + sec->_cooked_size + pad) | |||
1047 | <= sec->output_section->_raw_size)) | |||
1048 | { | |||
1049 | /* Find the last CIE/FDE. */ | |||
1050 | for (i = sec_info->count - 1; i > 0; i--) | |||
1051 | if (! sec_info->entry[i].removed) | |||
1052 | break; | |||
1053 | ||||
1054 | /* The size of the last CIE/FDE must be at least 4. */ | |||
1055 | if (sec_info->entry[i].removed | |||
1056 | || sec_info->entry[i].size < 4) | |||
1057 | abort ()_bfd_abort ("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" , 1057, __PRETTY_FUNCTION__); | |||
1058 | ||||
1059 | pad = alignment - pad; | |||
1060 | ||||
1061 | buf = contents + sec_info->entry[i].new_offset; | |||
1062 | ||||
1063 | /* Update length. */ | |||
1064 | sec_info->entry[i].size += pad; | |||
1065 | bfd_put_32 (abfd, sec_info->entry[i].size - 4, buf)((*((abfd)->xvec->bfd_putx32)) ((sec_info->entry[i]. size - 4),(buf))); | |||
1066 | ||||
1067 | /* Pad it with DW_CFA_nop */ | |||
1068 | memset (p, 0, pad); | |||
1069 | p += pad; | |||
1070 | ||||
1071 | sec->_cooked_size += pad; | |||
1072 | } | |||
1073 | } | |||
1074 | ||||
1075 | BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size){ if (!((bfd_size_type) (p - contents) == sec->_cooked_size )) bfd_assert("/usr/src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c" ,1075); }; | |||
1076 | ||||
1077 | return bfd_set_section_contents (abfd, sec->output_section, | |||
1078 | contents, (file_ptr) sec->output_offset, | |||
1079 | sec->_cooked_size); | |||
1080 | } | |||
1081 | ||||
1082 | /* Helper function used to sort .eh_frame_hdr search table by increasing | |||
1083 | VMA of FDE initial location. */ | |||
1084 | ||||
1085 | static int | |||
1086 | vma_compare (const void *a, const void *b) | |||
1087 | { | |||
1088 | const struct eh_frame_array_ent *p = a; | |||
1089 | const struct eh_frame_array_ent *q = b; | |||
1090 | if (p->initial_loc > q->initial_loc) | |||
1091 | return 1; | |||
1092 | if (p->initial_loc < q->initial_loc) | |||
1093 | return -1; | |||
1094 | return 0; | |||
1095 | } | |||
1096 | ||||
1097 | /* Write out .eh_frame_hdr section. This must be called after | |||
1098 | _bfd_elf_write_section_eh_frame has been called on all input | |||
1099 | .eh_frame sections. | |||
1100 | .eh_frame_hdr format: | |||
1101 | ubyte version (currently 1) | |||
1102 | ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of | |||
1103 | .eh_frame section) | |||
1104 | ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count | |||
1105 | number (or DW_EH_PE_omit if there is no | |||
1106 | binary search table computed)) | |||
1107 | ubyte table_enc (DW_EH_PE_* encoding of binary search table, | |||
1108 | or DW_EH_PE_omit if not present. | |||
1109 | DW_EH_PE_datarel is using address of | |||
1110 | .eh_frame_hdr section start as base) | |||
1111 | [encoded] eh_frame_ptr (pointer to start of .eh_frame section) | |||
1112 | optionally followed by: | |||
1113 | [encoded] fde_count (total number of FDEs in .eh_frame section) | |||
1114 | fde_count x [encoded] initial_loc, fde | |||
1115 | (array of encoded pairs containing | |||
1116 | FDE initial_location field and FDE address, | |||
1117 | sorted by increasing initial_loc). */ | |||
1118 | ||||
1119 | bfd_boolean | |||
1120 | _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) | |||
1121 | { | |||
1122 | struct elf_link_hash_table *htab; | |||
1123 | struct eh_frame_hdr_info *hdr_info; | |||
1124 | asection *sec; | |||
1125 | bfd_byte *contents; | |||
1126 | asection *eh_frame_sec; | |||
1127 | bfd_size_type size; | |||
1128 | bfd_boolean retval; | |||
1129 | bfd_vma encoded_eh_frame; | |||
1130 | ||||
1131 | htab = elf_hash_table (info)((struct elf_link_hash_table *) ((info)->hash)); | |||
1132 | hdr_info = &htab->eh_info; | |||
1133 | sec = hdr_info->hdr_sec; | |||
1134 | if (sec == NULL((void*)0)) | |||
| ||||
1135 | return TRUE1; | |||
1136 | ||||
1137 | size = EH_FRAME_HDR_SIZE8; | |||
1138 | if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) | |||
1139 | size += 4 + hdr_info->fde_count * 8; | |||
1140 | contents = bfd_malloc (size); | |||
1141 | if (contents == NULL((void*)0)) | |||
1142 | return FALSE0; | |||
1143 | ||||
1144 | eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); | |||
1145 | if (eh_frame_sec == NULL((void*)0)) | |||
1146 | { | |||
1147 | free (contents); | |||
1148 | return FALSE0; | |||
1149 | } | |||
1150 | ||||
1151 | memset (contents, 0, EH_FRAME_HDR_SIZE8); | |||
1152 | contents[0] = 1; /* Version. */ | |||
1153 | contents[1] = get_elf_backend_data (abfd)((const struct elf_backend_data *) (abfd)->xvec->backend_data )->elf_backend_encode_eh_address | |||
1154 | (abfd, info, eh_frame_sec, 0, sec, 4, | |||
1155 | &encoded_eh_frame); /* .eh_frame offset. */ | |||
1156 | ||||
1157 | if (hdr_info->array
| |||
1158 | { | |||
1159 | contents[2] = DW_EH_PE_udata40x03; /* FDE count encoding. */ | |||
1160 | contents[3] = DW_EH_PE_datarel0x30 | DW_EH_PE_sdata40x0B; /* Search table enc. */ | |||
1161 | } | |||
1162 | else | |||
1163 | { | |||
1164 | contents[2] = DW_EH_PE_omit0xff; | |||
1165 | contents[3] = DW_EH_PE_omit0xff; | |||
1166 | } | |||
1167 | bfd_put_32 (abfd, encoded_eh_frame, contents + 4)((*((abfd)->xvec->bfd_putx32)) ((encoded_eh_frame),(contents + 4))); | |||
1168 | ||||
1169 | if (contents[2] != DW_EH_PE_omit0xff) | |||
1170 | { | |||
1171 | unsigned int i; | |||
1172 | ||||
1173 | bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE)((*((abfd)->xvec->bfd_putx32)) ((hdr_info->fde_count ),(contents + 8))); | |||
1174 | qsort (hdr_info->array, hdr_info->fde_count, sizeof (*hdr_info->array), | |||
1175 | vma_compare); | |||
1176 | for (i = 0; i < hdr_info->fde_count; i++) | |||
1177 | { | |||
1178 | bfd_put_32 (abfd,((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. initial_loc - sec->output_section->vma),(contents + 8 + i * 8 + 4))) | |||
| ||||
1179 | hdr_info->array[i].initial_loc((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. initial_loc - sec->output_section->vma),(contents + 8 + i * 8 + 4))) | |||
1180 | - sec->output_section->vma,((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. initial_loc - sec->output_section->vma),(contents + 8 + i * 8 + 4))) | |||
1181 | contents + EH_FRAME_HDR_SIZE + i * 8 + 4)((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. initial_loc - sec->output_section->vma),(contents + 8 + i * 8 + 4))); | |||
1182 | bfd_put_32 (abfd,((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. fde - sec->output_section->vma),(contents + 8 + i * 8 + 8))) | |||
1183 | hdr_info->array[i].fde - sec->output_section->vma,((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. fde - sec->output_section->vma),(contents + 8 + i * 8 + 8))) | |||
1184 | contents + EH_FRAME_HDR_SIZE + i * 8 + 8)((*((abfd)->xvec->bfd_putx32)) ((hdr_info->array[i]. fde - sec->output_section->vma),(contents + 8 + i * 8 + 8))); | |||
1185 | } | |||
1186 | } | |||
1187 | ||||
1188 | retval = bfd_set_section_contents (abfd, sec->output_section, | |||
1189 | contents, (file_ptr) sec->output_offset, | |||
1190 | sec->_cooked_size); | |||
1191 | free (contents); | |||
1192 | return retval; | |||
1193 | } | |||
1194 | ||||
1195 | /* Decide whether we can use a PC-relative encoding within the given | |||
1196 | EH frame section. This is the default implementation. */ | |||
1197 | ||||
1198 | bfd_boolean | |||
1199 | _bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
1200 | struct bfd_link_info *info ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
1201 | asection *eh_frame_section ATTRIBUTE_UNUSED__attribute__ ((__unused__))) | |||
1202 | { | |||
1203 | return TRUE1; | |||
1204 | } | |||
1205 | ||||
1206 | /* Select an encoding for the given address. Preference is given to | |||
1207 | PC-relative addressing modes. */ | |||
1208 | ||||
1209 | bfd_byte | |||
1210 | _bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
1211 | struct bfd_link_info *info ATTRIBUTE_UNUSED__attribute__ ((__unused__)), | |||
1212 | asection *osec, bfd_vma offset, | |||
1213 | asection *loc_sec, bfd_vma loc_offset, | |||
1214 | bfd_vma *encoded) | |||
1215 | { | |||
1216 | *encoded = osec->vma + offset - | |||
1217 | (loc_sec->output_section->vma + loc_sec->output_offset + loc_offset); | |||
1218 | return DW_EH_PE_pcrel0x10 | DW_EH_PE_sdata40x0B; | |||
1219 | } |