1 |
/* .eh_frame section optimization. |
/* .eh_frame section optimization. |
2 |
Copyright 2001, 2002 Free Software Foundation, Inc. |
Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. |
3 |
Written by Jakub Jelinek <jakub@redhat.com>. |
Written by Jakub Jelinek <jakub@redhat.com>. |
4 |
|
|
5 |
This file is part of BFD, the Binary File Descriptor library. |
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 |
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 |
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 |
the Free Software Foundation; either version 2 of the License, or |
10 |
(at your option) any later version. |
(at your option) any later version. |
11 |
|
|
12 |
This program is distributed in the hope that it will be useful, |
This program is distributed in the hope that it will be useful, |
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
GNU General Public License for more details. |
GNU General Public License for more details. |
16 |
|
|
17 |
You should have received a copy of the GNU General Public License |
You should have received a copy of the GNU General Public License |
18 |
along with this program; if not, write to the Free Software |
along with this program; if not, write to the Free Software |
19 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
20 |
|
|
21 |
#include "bfd.h" |
#include "bfd.h" |
22 |
#include "sysdep.h" |
#include "sysdep.h" |
26 |
|
|
27 |
#define EH_FRAME_HDR_SIZE 8 |
#define EH_FRAME_HDR_SIZE 8 |
28 |
|
|
29 |
struct cie_header |
/* If *ITER hasn't reached END yet, read the next byte into *RESULT and |
30 |
{ |
move onto the next byte. Return true on success. */ |
|
unsigned int length; |
|
|
unsigned int id; |
|
|
}; |
|
31 |
|
|
32 |
struct cie |
static inline bfd_boolean |
33 |
|
read_byte (bfd_byte **iter, bfd_byte *end, unsigned char *result) |
34 |
{ |
{ |
35 |
struct cie_header hdr; |
if (*iter >= end) |
36 |
unsigned char version; |
return FALSE; |
37 |
unsigned char augmentation[20]; |
*result = *((*iter)++); |
38 |
unsigned int code_align; |
return TRUE; |
39 |
int data_align; |
} |
|
unsigned int ra_column; |
|
|
unsigned int augmentation_size; |
|
|
struct elf_link_hash_entry *personality; |
|
|
unsigned char per_encoding; |
|
|
unsigned char lsda_encoding; |
|
|
unsigned char fde_encoding; |
|
|
unsigned char initial_insn_length; |
|
|
unsigned char make_relative; |
|
|
unsigned char make_lsda_relative; |
|
|
unsigned char initial_instructions[50]; |
|
|
}; |
|
40 |
|
|
41 |
struct eh_cie_fde |
/* Move *ITER over LENGTH bytes, or up to END, whichever is closer. |
42 |
|
Return true it was possible to move LENGTH bytes. */ |
43 |
|
|
44 |
|
static inline bfd_boolean |
45 |
|
skip_bytes (bfd_byte **iter, bfd_byte *end, bfd_size_type length) |
46 |
{ |
{ |
47 |
unsigned int offset; |
if ((bfd_size_type) (end - *iter) < length) |
48 |
unsigned int size; |
{ |
49 |
asection *sec; |
*iter = end; |
50 |
unsigned int new_offset; |
return FALSE; |
51 |
unsigned char fde_encoding; |
} |
52 |
unsigned char lsda_encoding; |
*iter += length; |
53 |
unsigned char lsda_offset; |
return TRUE; |
54 |
unsigned char cie : 1; |
} |
|
unsigned char removed : 1; |
|
|
unsigned char make_relative : 1; |
|
|
unsigned char make_lsda_relative : 1; |
|
|
unsigned char per_encoding_relative : 1; |
|
|
}; |
|
|
|
|
|
struct eh_frame_sec_info |
|
|
{ |
|
|
unsigned int count; |
|
|
unsigned int alloced; |
|
|
struct eh_cie_fde entry[1]; |
|
|
}; |
|
|
|
|
|
struct eh_frame_array_ent |
|
|
{ |
|
|
bfd_vma initial_loc; |
|
|
bfd_vma fde; |
|
|
}; |
|
|
|
|
|
struct eh_frame_hdr_info |
|
|
{ |
|
|
struct cie last_cie; |
|
|
asection *last_cie_sec; |
|
|
unsigned int last_cie_offset; |
|
|
unsigned int fde_count, array_count; |
|
|
struct eh_frame_array_ent *array; |
|
|
/* TRUE if .eh_frame_hdr should contain the sorted search table. |
|
|
We build it if we successfully read all .eh_frame input sections |
|
|
and recognize them. */ |
|
|
boolean table; |
|
|
boolean strip; |
|
|
}; |
|
|
|
|
|
static bfd_vma read_unsigned_leb128 |
|
|
PARAMS ((bfd *, char *, unsigned int *)); |
|
|
static bfd_signed_vma read_signed_leb128 |
|
|
PARAMS ((bfd *, char *, unsigned int *)); |
|
|
static int get_DW_EH_PE_width |
|
|
PARAMS ((int, int)); |
|
|
static bfd_vma read_value |
|
|
PARAMS ((bfd *, bfd_byte *, int)); |
|
|
static void write_value |
|
|
PARAMS ((bfd *, bfd_byte *, bfd_vma, int)); |
|
|
static int cie_compare |
|
|
PARAMS ((struct cie *, struct cie *)); |
|
|
static int vma_compare |
|
|
PARAMS ((const PTR a, const PTR b)); |
|
55 |
|
|
56 |
/* Helper function for reading uleb128 encoded data. */ |
/* Move *ITER over an leb128, stopping at END. Return true if the end |
57 |
|
of the leb128 was found. */ |
58 |
|
|
59 |
static bfd_vma |
static bfd_boolean |
60 |
read_unsigned_leb128 (abfd, buf, bytes_read_ptr) |
skip_leb128 (bfd_byte **iter, bfd_byte *end) |
61 |
bfd *abfd ATTRIBUTE_UNUSED; |
{ |
|
char *buf; |
|
|
unsigned int *bytes_read_ptr; |
|
|
{ |
|
|
bfd_vma result; |
|
|
unsigned int num_read; |
|
|
int shift; |
|
62 |
unsigned char byte; |
unsigned char byte; |
|
|
|
|
result = 0; |
|
|
shift = 0; |
|
|
num_read = 0; |
|
63 |
do |
do |
64 |
{ |
if (!read_byte (iter, end, &byte)) |
65 |
byte = bfd_get_8 (abfd, (bfd_byte *) buf); |
return FALSE; |
|
buf ++; |
|
|
num_read ++; |
|
|
result |= (((bfd_vma) byte & 0x7f) << shift); |
|
|
shift += 7; |
|
|
} |
|
66 |
while (byte & 0x80); |
while (byte & 0x80); |
67 |
* bytes_read_ptr = num_read; |
return TRUE; |
|
return result; |
|
68 |
} |
} |
69 |
|
|
70 |
/* Helper function for reading sleb128 encoded data. */ |
/* Like skip_leb128, but treat the leb128 as an unsigned value and |
71 |
|
store it in *VALUE. */ |
72 |
|
|
73 |
static bfd_signed_vma |
static bfd_boolean |
74 |
read_signed_leb128 (abfd, buf, bytes_read_ptr) |
read_uleb128 (bfd_byte **iter, bfd_byte *end, bfd_vma *value) |
|
bfd *abfd ATTRIBUTE_UNUSED; |
|
|
char *buf; |
|
|
unsigned int * bytes_read_ptr; |
|
75 |
{ |
{ |
76 |
bfd_vma result; |
bfd_byte *start, *p; |
|
int shift; |
|
|
int num_read; |
|
|
unsigned char byte; |
|
77 |
|
|
78 |
result = 0; |
start = *iter; |
79 |
shift = 0; |
if (!skip_leb128 (iter, end)) |
80 |
num_read = 0; |
return FALSE; |
81 |
do |
|
82 |
{ |
p = *iter; |
83 |
byte = bfd_get_8 (abfd, (bfd_byte *) buf); |
*value = *--p; |
84 |
buf ++; |
while (p > start) |
85 |
num_read ++; |
*value = (*value << 7) | (*--p & 0x7f); |
86 |
result |= (((bfd_vma) byte & 0x7f) << shift); |
|
87 |
shift += 7; |
return TRUE; |
88 |
} |
} |
89 |
while (byte & 0x80); |
|
90 |
if (byte & 0x40) |
/* Like read_uleb128, but for signed values. */ |
91 |
result |= (((bfd_vma) -1) << (shift - 7)) << 7; |
|
92 |
* bytes_read_ptr = num_read; |
static bfd_boolean |
93 |
return result; |
read_sleb128 (bfd_byte **iter, bfd_byte *end, bfd_signed_vma *value) |
94 |
} |
{ |
95 |
|
bfd_byte *start, *p; |
96 |
#define read_uleb128(VAR, BUF) \ |
|
97 |
do \ |
start = *iter; |
98 |
{ \ |
if (!skip_leb128 (iter, end)) |
99 |
(VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp); \ |
return FALSE; |
100 |
(BUF) += leb128_tmp; \ |
|
101 |
} \ |
p = *iter; |
102 |
while (0) |
*value = ((*--p & 0x7f) ^ 0x40) - 0x40; |
103 |
|
while (p > start) |
104 |
#define read_sleb128(VAR, BUF) \ |
*value = (*value << 7) | (*--p & 0x7f); |
105 |
do \ |
|
106 |
{ \ |
return TRUE; |
107 |
(VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); \ |
} |
|
(BUF) += leb128_tmp; \ |
|
|
} \ |
|
|
while (0) |
|
108 |
|
|
109 |
/* Return 0 if either encoding is variable width, or not yet known to bfd. */ |
/* Return 0 if either encoding is variable width, or not yet known to bfd. */ |
110 |
|
|
111 |
static |
static |
112 |
int get_DW_EH_PE_width (encoding, ptr_size) |
int get_DW_EH_PE_width (int encoding, int ptr_size) |
|
int encoding, ptr_size; |
|
113 |
{ |
{ |
114 |
/* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame |
/* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame |
115 |
was added to bfd. */ |
was added to bfd. */ |
129 |
return 0; |
return 0; |
130 |
} |
} |
131 |
|
|
132 |
|
#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0) |
133 |
|
|
134 |
/* Read a width sized value from memory. */ |
/* Read a width sized value from memory. */ |
135 |
|
|
136 |
static bfd_vma |
static bfd_vma |
137 |
read_value (abfd, buf, width) |
read_value (bfd *abfd, bfd_byte *buf, int width, int is_signed) |
|
bfd *abfd; |
|
|
bfd_byte *buf; |
|
|
int width; |
|
138 |
{ |
{ |
139 |
bfd_vma value; |
bfd_vma value; |
140 |
|
|
141 |
switch (width) |
switch (width) |
142 |
{ |
{ |
143 |
case 2: value = bfd_get_16 (abfd, buf); break; |
case 2: |
144 |
case 4: value = bfd_get_32 (abfd, buf); break; |
if (is_signed) |
145 |
case 8: value = bfd_get_64 (abfd, buf); break; |
value = bfd_get_signed_16 (abfd, buf); |
146 |
default: BFD_FAIL (); return 0; |
else |
147 |
|
value = bfd_get_16 (abfd, buf); |
148 |
|
break; |
149 |
|
case 4: |
150 |
|
if (is_signed) |
151 |
|
value = bfd_get_signed_32 (abfd, buf); |
152 |
|
else |
153 |
|
value = bfd_get_32 (abfd, buf); |
154 |
|
break; |
155 |
|
case 8: |
156 |
|
if (is_signed) |
157 |
|
value = bfd_get_signed_64 (abfd, buf); |
158 |
|
else |
159 |
|
value = bfd_get_64 (abfd, buf); |
160 |
|
break; |
161 |
|
default: |
162 |
|
BFD_FAIL (); |
163 |
|
return 0; |
164 |
} |
} |
165 |
|
|
166 |
return value; |
return value; |
167 |
} |
} |
168 |
|
|
169 |
/* Store a width sized value to memory. */ |
/* Store a width sized value to memory. */ |
170 |
|
|
171 |
static void |
static void |
172 |
write_value (abfd, buf, value, width) |
write_value (bfd *abfd, bfd_byte *buf, bfd_vma value, int width) |
|
bfd *abfd; |
|
|
bfd_byte *buf; |
|
|
bfd_vma value; |
|
|
int width; |
|
173 |
{ |
{ |
174 |
switch (width) |
switch (width) |
175 |
{ |
{ |
183 |
/* Return zero if C1 and C2 CIEs can be merged. */ |
/* Return zero if C1 and C2 CIEs can be merged. */ |
184 |
|
|
185 |
static |
static |
186 |
int cie_compare (c1, c2) |
int cie_compare (struct cie *c1, struct cie *c2) |
|
struct cie *c1, *c2; |
|
187 |
{ |
{ |
188 |
if (c1->hdr.length == c2->hdr.length |
if (c1->hdr.length == c2->hdr.length |
189 |
&& c1->version == c2->version |
&& c1->version == c2->version |
197 |
&& c1->per_encoding == c2->per_encoding |
&& c1->per_encoding == c2->per_encoding |
198 |
&& c1->lsda_encoding == c2->lsda_encoding |
&& c1->lsda_encoding == c2->lsda_encoding |
199 |
&& c1->fde_encoding == c2->fde_encoding |
&& c1->fde_encoding == c2->fde_encoding |
200 |
&& (c1->initial_insn_length |
&& c1->initial_insn_length == c2->initial_insn_length |
|
== c2->initial_insn_length) |
|
201 |
&& memcmp (c1->initial_instructions, |
&& memcmp (c1->initial_instructions, |
202 |
c2->initial_instructions, |
c2->initial_instructions, |
203 |
c1->initial_insn_length) == 0) |
c1->initial_insn_length) == 0) |
206 |
return 1; |
return 1; |
207 |
} |
} |
208 |
|
|
209 |
|
/* Return the number of extra bytes that we'll be inserting into |
210 |
|
ENTRY's augmentation string. */ |
211 |
|
|
212 |
|
static INLINE unsigned int |
213 |
|
extra_augmentation_string_bytes (struct eh_cie_fde *entry) |
214 |
|
{ |
215 |
|
unsigned int size = 0; |
216 |
|
if (entry->cie) |
217 |
|
{ |
218 |
|
if (entry->add_augmentation_size) |
219 |
|
size++; |
220 |
|
if (entry->add_fde_encoding) |
221 |
|
size++; |
222 |
|
} |
223 |
|
return size; |
224 |
|
} |
225 |
|
|
226 |
|
/* Likewise ENTRY's augmentation data. */ |
227 |
|
|
228 |
|
static INLINE unsigned int |
229 |
|
extra_augmentation_data_bytes (struct eh_cie_fde *entry) |
230 |
|
{ |
231 |
|
unsigned int size = 0; |
232 |
|
if (entry->cie) |
233 |
|
{ |
234 |
|
if (entry->add_augmentation_size) |
235 |
|
size++; |
236 |
|
if (entry->add_fde_encoding) |
237 |
|
size++; |
238 |
|
} |
239 |
|
else |
240 |
|
{ |
241 |
|
if (entry->cie_inf->add_augmentation_size) |
242 |
|
size++; |
243 |
|
} |
244 |
|
return size; |
245 |
|
} |
246 |
|
|
247 |
|
/* Return the size that ENTRY will have in the output. ALIGNMENT is the |
248 |
|
required alignment of ENTRY in bytes. */ |
249 |
|
|
250 |
|
static unsigned int |
251 |
|
size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) |
252 |
|
{ |
253 |
|
if (entry->removed) |
254 |
|
return 0; |
255 |
|
if (entry->size == 4) |
256 |
|
return 4; |
257 |
|
return (entry->size |
258 |
|
+ extra_augmentation_string_bytes (entry) |
259 |
|
+ extra_augmentation_data_bytes (entry) |
260 |
|
+ alignment - 1) & -alignment; |
261 |
|
} |
262 |
|
|
263 |
|
/* Assume that the bytes between *ITER and END are CFA instructions. |
264 |
|
Try to move *ITER past the first instruction and return true on |
265 |
|
success. ENCODED_PTR_WIDTH gives the width of pointer entries. */ |
266 |
|
|
267 |
|
static bfd_boolean |
268 |
|
skip_cfa_op (bfd_byte **iter, bfd_byte *end, unsigned int encoded_ptr_width) |
269 |
|
{ |
270 |
|
bfd_byte op; |
271 |
|
bfd_vma length; |
272 |
|
|
273 |
|
if (!read_byte (iter, end, &op)) |
274 |
|
return FALSE; |
275 |
|
|
276 |
|
switch (op & 0x80 ? op & 0xc0 : op) |
277 |
|
{ |
278 |
|
case DW_CFA_nop: |
279 |
|
case DW_CFA_advance_loc: |
280 |
|
case DW_CFA_restore: |
281 |
|
/* No arguments. */ |
282 |
|
return TRUE; |
283 |
|
|
284 |
|
case DW_CFA_offset: |
285 |
|
case DW_CFA_restore_extended: |
286 |
|
case DW_CFA_undefined: |
287 |
|
case DW_CFA_same_value: |
288 |
|
case DW_CFA_def_cfa_register: |
289 |
|
case DW_CFA_def_cfa_offset: |
290 |
|
case DW_CFA_def_cfa_offset_sf: |
291 |
|
case DW_CFA_GNU_args_size: |
292 |
|
/* One leb128 argument. */ |
293 |
|
return skip_leb128 (iter, end); |
294 |
|
|
295 |
|
case DW_CFA_offset_extended: |
296 |
|
case DW_CFA_register: |
297 |
|
case DW_CFA_def_cfa: |
298 |
|
case DW_CFA_offset_extended_sf: |
299 |
|
case DW_CFA_GNU_negative_offset_extended: |
300 |
|
case DW_CFA_def_cfa_sf: |
301 |
|
/* Two leb128 arguments. */ |
302 |
|
return (skip_leb128 (iter, end) |
303 |
|
&& skip_leb128 (iter, end)); |
304 |
|
|
305 |
|
case DW_CFA_def_cfa_expression: |
306 |
|
/* A variable-length argument. */ |
307 |
|
return (read_uleb128 (iter, end, &length) |
308 |
|
&& skip_bytes (iter, end, length)); |
309 |
|
|
310 |
|
case DW_CFA_expression: |
311 |
|
/* A leb128 followed by a variable-length argument. */ |
312 |
|
return (skip_leb128 (iter, end) |
313 |
|
&& read_uleb128 (iter, end, &length) |
314 |
|
&& skip_bytes (iter, end, length)); |
315 |
|
|
316 |
|
case DW_CFA_set_loc: |
317 |
|
return skip_bytes (iter, end, encoded_ptr_width); |
318 |
|
|
319 |
|
case DW_CFA_advance_loc1: |
320 |
|
return skip_bytes (iter, end, 1); |
321 |
|
|
322 |
|
case DW_CFA_advance_loc2: |
323 |
|
return skip_bytes (iter, end, 2); |
324 |
|
|
325 |
|
case DW_CFA_advance_loc4: |
326 |
|
return skip_bytes (iter, end, 4); |
327 |
|
|
328 |
|
case DW_CFA_MIPS_advance_loc8: |
329 |
|
return skip_bytes (iter, end, 8); |
330 |
|
|
331 |
|
default: |
332 |
|
return FALSE; |
333 |
|
} |
334 |
|
} |
335 |
|
|
336 |
|
/* Try to interpret the bytes between BUF and END as CFA instructions. |
337 |
|
If every byte makes sense, return a pointer to the first DW_CFA_nop |
338 |
|
padding byte, or END if there is no padding. Return null otherwise. |
339 |
|
ENCODED_PTR_WIDTH is as for skip_cfa_op. */ |
340 |
|
|
341 |
|
static bfd_byte * |
342 |
|
skip_non_nops (bfd_byte *buf, bfd_byte *end, unsigned int encoded_ptr_width) |
343 |
|
{ |
344 |
|
bfd_byte *last; |
345 |
|
|
346 |
|
last = buf; |
347 |
|
while (buf < end) |
348 |
|
if (*buf == DW_CFA_nop) |
349 |
|
buf++; |
350 |
|
else |
351 |
|
{ |
352 |
|
if (!skip_cfa_op (&buf, end, encoded_ptr_width)) |
353 |
|
return 0; |
354 |
|
last = buf; |
355 |
|
} |
356 |
|
return last; |
357 |
|
} |
358 |
|
|
359 |
/* This function is called for each input file before the .eh_frame |
/* This function is called for each input file before the .eh_frame |
360 |
section is relocated. It discards duplicate CIEs and FDEs for discarded |
section is relocated. It discards duplicate CIEs and FDEs for discarded |
361 |
functions. The function returns true iff any entries have been |
functions. The function returns TRUE iff any entries have been |
362 |
deleted. */ |
deleted. */ |
363 |
|
|
364 |
boolean |
bfd_boolean |
365 |
_bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec, |
_bfd_elf_discard_section_eh_frame |
366 |
reloc_symbol_deleted_p, cookie) |
(bfd *abfd, struct bfd_link_info *info, asection *sec, |
367 |
bfd *abfd; |
bfd_boolean (*reloc_symbol_deleted_p) (bfd_vma, void *), |
368 |
struct bfd_link_info *info; |
struct elf_reloc_cookie *cookie) |
|
asection *sec, *ehdrsec; |
|
|
boolean (*reloc_symbol_deleted_p) (bfd_vma, PTR); |
|
|
struct elf_reloc_cookie *cookie; |
|
369 |
{ |
{ |
370 |
|
#define REQUIRE(COND) \ |
371 |
|
do \ |
372 |
|
if (!(COND)) \ |
373 |
|
goto free_no_table; \ |
374 |
|
while (0) |
375 |
|
|
376 |
bfd_byte *ehbuf = NULL, *buf; |
bfd_byte *ehbuf = NULL, *buf; |
377 |
bfd_byte *last_cie, *last_fde; |
bfd_byte *last_cie, *last_fde; |
378 |
|
struct eh_cie_fde *ent, *last_cie_inf, *this_inf; |
379 |
struct cie_header hdr; |
struct cie_header hdr; |
380 |
struct cie cie; |
struct cie cie; |
381 |
|
struct elf_link_hash_table *htab; |
382 |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_hdr_info *hdr_info; |
383 |
struct eh_frame_sec_info *sec_info = NULL; |
struct eh_frame_sec_info *sec_info = NULL; |
384 |
unsigned int leb128_tmp; |
unsigned int cie_usage_count, offset; |
|
unsigned int cie_usage_count, last_cie_ndx, i, offset; |
|
|
unsigned int make_relative, make_lsda_relative; |
|
|
Elf_Internal_Rela *rel; |
|
|
bfd_size_type new_size; |
|
385 |
unsigned int ptr_size; |
unsigned int ptr_size; |
386 |
|
|
387 |
if (sec->_raw_size == 0) |
if (sec->size == 0) |
388 |
{ |
{ |
389 |
/* This file does not contain .eh_frame information. */ |
/* This file does not contain .eh_frame information. */ |
390 |
return false; |
return FALSE; |
391 |
} |
} |
392 |
|
|
393 |
if ((sec->output_section != NULL |
if ((sec->output_section != NULL |
394 |
&& bfd_is_abs_section (sec->output_section))) |
&& bfd_is_abs_section (sec->output_section))) |
395 |
{ |
{ |
396 |
/* At least one of the sections is being discarded from the |
/* At least one of the sections is being discarded from the |
397 |
link, so we should just ignore them. */ |
link, so we should just ignore them. */ |
398 |
return false; |
return FALSE; |
399 |
} |
} |
400 |
|
|
401 |
BFD_ASSERT (elf_section_data (ehdrsec)->sec_info_type |
htab = elf_hash_table (info); |
402 |
== ELF_INFO_TYPE_EH_FRAME_HDR); |
hdr_info = &htab->eh_info; |
|
hdr_info = (struct eh_frame_hdr_info *) |
|
|
elf_section_data (ehdrsec)->sec_info; |
|
403 |
|
|
404 |
/* Read the frame unwind information from abfd. */ |
/* Read the frame unwind information from abfd. */ |
405 |
|
|
406 |
ehbuf = (bfd_byte *) bfd_malloc (sec->_raw_size); |
REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); |
|
if (ehbuf == NULL) |
|
|
goto free_no_table; |
|
|
|
|
|
if (! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0, |
|
|
sec->_raw_size)) |
|
|
goto free_no_table; |
|
407 |
|
|
408 |
if (sec->_raw_size >= 4 |
if (sec->size >= 4 |
409 |
&& bfd_get_32 (abfd, ehbuf) == 0 |
&& bfd_get_32 (abfd, ehbuf) == 0 |
410 |
&& cookie->rel == cookie->relend) |
&& cookie->rel == cookie->relend) |
411 |
{ |
{ |
412 |
/* Empty .eh_frame section. */ |
/* Empty .eh_frame section. */ |
413 |
free (ehbuf); |
free (ehbuf); |
414 |
return false; |
return FALSE; |
415 |
} |
} |
416 |
|
|
417 |
/* If .eh_frame section size doesn't fit into int, we cannot handle |
/* If .eh_frame section size doesn't fit into int, we cannot handle |
418 |
it (it would need to use 64-bit .eh_frame format anyway). */ |
it (it would need to use 64-bit .eh_frame format anyway). */ |
419 |
if (sec->_raw_size != (unsigned int) sec->_raw_size) |
REQUIRE (sec->size == (unsigned int) sec->size); |
420 |
goto free_no_table; |
|
421 |
|
ptr_size = (get_elf_backend_data (abfd) |
422 |
|
->elf_backend_eh_frame_address_size (abfd, sec)); |
423 |
|
REQUIRE (ptr_size != 0); |
424 |
|
|
|
ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] |
|
|
== ELFCLASS64) ? 8 : 4; |
|
425 |
buf = ehbuf; |
buf = ehbuf; |
426 |
last_cie = NULL; |
last_cie = NULL; |
427 |
last_cie_ndx = 0; |
last_cie_inf = NULL; |
428 |
memset (&cie, 0, sizeof (cie)); |
memset (&cie, 0, sizeof (cie)); |
429 |
cie_usage_count = 0; |
cie_usage_count = 0; |
|
new_size = sec->_raw_size; |
|
|
make_relative = hdr_info->last_cie.make_relative; |
|
|
make_lsda_relative = hdr_info->last_cie.make_lsda_relative; |
|
430 |
sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) |
sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) |
431 |
+ 99 * sizeof (struct eh_cie_fde)); |
+ 99 * sizeof (struct eh_cie_fde)); |
432 |
if (sec_info == NULL) |
REQUIRE (sec_info); |
433 |
goto free_no_table; |
|
434 |
sec_info->alloced = 100; |
sec_info->alloced = 100; |
435 |
|
|
436 |
#define ENSURE_NO_RELOCS(buf) \ |
#define ENSURE_NO_RELOCS(buf) \ |
437 |
if (cookie->rel < cookie->relend \ |
REQUIRE (!(cookie->rel < cookie->relend \ |
438 |
&& (cookie->rel->r_offset \ |
&& (cookie->rel->r_offset \ |
439 |
< (bfd_size_type) ((buf) - ehbuf))) \ |
< (bfd_size_type) ((buf) - ehbuf)) \ |
440 |
goto free_no_table |
&& cookie->rel->r_info != 0)) |
441 |
|
|
442 |
#define SKIP_RELOCS(buf) \ |
#define SKIP_RELOCS(buf) \ |
443 |
while (cookie->rel < cookie->relend \ |
while (cookie->rel < cookie->relend \ |
444 |
&& (cookie->rel->r_offset \ |
&& (cookie->rel->r_offset \ |
445 |
< (bfd_size_type) ((buf) - ehbuf))) \ |
< (bfd_size_type) ((buf) - ehbuf))) \ |
446 |
cookie->rel++ |
cookie->rel++ |
447 |
|
|
448 |
#define GET_RELOC(buf) \ |
#define GET_RELOC(buf) \ |
449 |
((cookie->rel < cookie->relend \ |
((cookie->rel < cookie->relend \ |
450 |
&& (cookie->rel->r_offset \ |
&& (cookie->rel->r_offset \ |
451 |
== (bfd_size_type) ((buf) - ehbuf))) \ |
== (bfd_size_type) ((buf) - ehbuf))) \ |
452 |
? cookie->rel : NULL) |
? cookie->rel : NULL) |
453 |
|
|
454 |
for (;;) |
for (;;) |
455 |
{ |
{ |
456 |
unsigned char *aug; |
char *aug; |
457 |
|
bfd_byte *start, *end, *insns; |
458 |
|
bfd_size_type length; |
459 |
|
|
460 |
if (sec_info->count == sec_info->alloced) |
if (sec_info->count == sec_info->alloced) |
461 |
{ |
{ |
462 |
|
struct eh_cie_fde *old_entry = sec_info->entry; |
463 |
sec_info = bfd_realloc (sec_info, |
sec_info = bfd_realloc (sec_info, |
464 |
sizeof (struct eh_frame_sec_info) |
sizeof (struct eh_frame_sec_info) |
465 |
+ (sec_info->alloced + 99) |
+ ((sec_info->alloced + 99) |
466 |
* sizeof (struct eh_cie_fde)); |
* sizeof (struct eh_cie_fde))); |
467 |
if (sec_info == NULL) |
REQUIRE (sec_info); |
|
goto free_no_table; |
|
468 |
|
|
469 |
memset (&sec_info->entry[sec_info->alloced], 0, |
memset (&sec_info->entry[sec_info->alloced], 0, |
470 |
100 * sizeof (struct eh_cie_fde)); |
100 * sizeof (struct eh_cie_fde)); |
471 |
sec_info->alloced += 100; |
sec_info->alloced += 100; |
472 |
|
|
473 |
|
/* Now fix any pointers into the array. */ |
474 |
|
if (last_cie_inf >= old_entry |
475 |
|
&& last_cie_inf < old_entry + sec_info->count) |
476 |
|
last_cie_inf = sec_info->entry + (last_cie_inf - old_entry); |
477 |
} |
} |
478 |
|
|
479 |
|
this_inf = sec_info->entry + sec_info->count; |
480 |
last_fde = buf; |
last_fde = buf; |
481 |
/* If we are at the end of the section, we still need to decide |
/* If we are at the end of the section, we still need to decide |
482 |
on whether to output or discard last encountered CIE (if any). */ |
on whether to output or discard last encountered CIE (if any). */ |
483 |
if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size) |
if ((bfd_size_type) (buf - ehbuf) == sec->size) |
484 |
hdr.id = (unsigned int) -1; |
{ |
485 |
|
hdr.length = 0; |
486 |
|
hdr.id = (unsigned int) -1; |
487 |
|
end = buf; |
488 |
|
} |
489 |
else |
else |
490 |
{ |
{ |
491 |
if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) |
/* Read the length of the entry. */ |
492 |
/* No space for CIE/FDE header length. */ |
REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); |
493 |
goto free_no_table; |
hdr.length = bfd_get_32 (abfd, buf - 4); |
494 |
|
|
495 |
hdr.length = bfd_get_32 (abfd, buf); |
/* 64-bit .eh_frame is not supported. */ |
496 |
if (hdr.length == 0xffffffff) |
REQUIRE (hdr.length != 0xffffffff); |
497 |
/* 64-bit .eh_frame is not supported. */ |
|
498 |
goto free_no_table; |
/* The CIE/FDE must be fully contained in this input section. */ |
499 |
buf += 4; |
REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size); |
500 |
if ((buf - ehbuf) + hdr.length > sec->_raw_size) |
end = buf + hdr.length; |
|
/* CIE/FDE not contained fully in this .eh_frame input section. */ |
|
|
goto free_no_table; |
|
501 |
|
|
502 |
sec_info->entry[sec_info->count].offset = last_fde - ehbuf; |
this_inf->offset = last_fde - ehbuf; |
503 |
sec_info->entry[sec_info->count].size = 4 + hdr.length; |
this_inf->size = 4 + hdr.length; |
504 |
|
|
505 |
if (hdr.length == 0) |
if (hdr.length == 0) |
506 |
{ |
{ |
507 |
/* CIE with length 0 must be only the last in the section. */ |
/* A zero-length CIE should only be found at the end of |
508 |
if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) |
the section. */ |
509 |
goto free_no_table; |
REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); |
510 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
511 |
sec_info->count++; |
sec_info->count++; |
512 |
/* Now just finish last encountered CIE processing and break |
/* Now just finish last encountered CIE processing and break |
515 |
} |
} |
516 |
else |
else |
517 |
{ |
{ |
518 |
hdr.id = bfd_get_32 (abfd, buf); |
REQUIRE (skip_bytes (&buf, end, 4)); |
519 |
buf += 4; |
hdr.id = bfd_get_32 (abfd, buf - 4); |
520 |
if (hdr.id == (unsigned int) -1) |
REQUIRE (hdr.id != (unsigned int) -1); |
|
goto free_no_table; |
|
521 |
} |
} |
522 |
} |
} |
523 |
|
|
528 |
/* CIE */ |
/* CIE */ |
529 |
if (last_cie != NULL) |
if (last_cie != NULL) |
530 |
{ |
{ |
531 |
/* Now check if this CIE is identical to last CIE, in which case |
/* Now check if this CIE is identical to the last CIE, |
532 |
we can remove it, provided we adjust all FDEs. |
in which case we can remove it provided we adjust |
533 |
Also, it can be removed if we have removed all FDEs using |
all FDEs. Also, it can be removed if we have removed |
534 |
that. */ |
all FDEs using it. */ |
535 |
if (cie_compare (&cie, &hdr_info->last_cie) == 0 |
if ((!info->relocatable |
536 |
|
&& hdr_info->last_cie_sec |
537 |
|
&& (sec->output_section |
538 |
|
== hdr_info->last_cie_sec->output_section) |
539 |
|
&& cie_compare (&cie, &hdr_info->last_cie) == 0) |
540 |
|| cie_usage_count == 0) |
|| cie_usage_count == 0) |
541 |
{ |
last_cie_inf->removed = 1; |
|
new_size -= cie.hdr.length + 4; |
|
|
sec_info->entry[last_cie_ndx].removed = 1; |
|
|
sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; |
|
|
sec_info->entry[last_cie_ndx].new_offset |
|
|
= hdr_info->last_cie_offset; |
|
|
} |
|
542 |
else |
else |
543 |
{ |
{ |
544 |
hdr_info->last_cie = cie; |
hdr_info->last_cie = cie; |
545 |
hdr_info->last_cie_sec = sec; |
hdr_info->last_cie_sec = sec; |
546 |
hdr_info->last_cie_offset = last_cie - ehbuf; |
last_cie_inf->make_relative = cie.make_relative; |
547 |
sec_info->entry[last_cie_ndx].make_relative |
last_cie_inf->make_lsda_relative = cie.make_lsda_relative; |
548 |
= cie.make_relative; |
last_cie_inf->per_encoding_relative |
|
sec_info->entry[last_cie_ndx].make_lsda_relative |
|
|
= cie.make_lsda_relative; |
|
|
sec_info->entry[last_cie_ndx].per_encoding_relative |
|
549 |
= (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; |
= (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; |
550 |
} |
} |
551 |
} |
} |
553 |
if (hdr.id == (unsigned int) -1) |
if (hdr.id == (unsigned int) -1) |
554 |
break; |
break; |
555 |
|
|
556 |
last_cie_ndx = sec_info->count; |
last_cie_inf = this_inf; |
557 |
sec_info->entry[sec_info->count].cie = 1; |
this_inf->cie = 1; |
558 |
|
|
559 |
cie_usage_count = 0; |
cie_usage_count = 0; |
560 |
memset (&cie, 0, sizeof (cie)); |
memset (&cie, 0, sizeof (cie)); |
561 |
cie.hdr = hdr; |
cie.hdr = hdr; |
562 |
cie.version = *buf++; |
REQUIRE (read_byte (&buf, end, &cie.version)); |
563 |
|
|
564 |
/* Cannot handle unknown versions. */ |
/* Cannot handle unknown versions. */ |
565 |
if (cie.version != 1) |
REQUIRE (cie.version == 1 || cie.version == 3); |
566 |
goto free_no_table; |
REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation)); |
|
if (strlen (buf) > sizeof (cie.augmentation) - 1) |
|
|
goto free_no_table; |
|
567 |
|
|
568 |
strcpy (cie.augmentation, buf); |
strcpy (cie.augmentation, (char *) buf); |
569 |
buf = strchr (buf, '\0') + 1; |
buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; |
570 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
571 |
if (buf[0] == 'e' && buf[1] == 'h') |
if (buf[0] == 'e' && buf[1] == 'h') |
572 |
{ |
{ |
574 |
/* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ |
/* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ |
575 |
is private to each CIE, so we don't need it for anything. |
is private to each CIE, so we don't need it for anything. |
576 |
Just skip it. */ |
Just skip it. */ |
577 |
buf += ptr_size; |
REQUIRE (skip_bytes (&buf, end, ptr_size)); |
578 |
SKIP_RELOCS (buf); |
SKIP_RELOCS (buf); |
579 |
} |
} |
580 |
read_uleb128 (cie.code_align, buf); |
REQUIRE (read_uleb128 (&buf, end, &cie.code_align)); |
581 |
read_sleb128 (cie.data_align, buf); |
REQUIRE (read_sleb128 (&buf, end, &cie.data_align)); |
582 |
read_uleb128 (cie.ra_column, buf); |
if (cie.version == 1) |
583 |
|
{ |
584 |
|
REQUIRE (buf < end); |
585 |
|
cie.ra_column = *buf++; |
586 |
|
} |
587 |
|
else |
588 |
|
REQUIRE (read_uleb128 (&buf, end, &cie.ra_column)); |
589 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
590 |
cie.lsda_encoding = DW_EH_PE_omit; |
cie.lsda_encoding = DW_EH_PE_omit; |
591 |
cie.fde_encoding = DW_EH_PE_omit; |
cie.fde_encoding = DW_EH_PE_omit; |
596 |
if (*aug == 'z') |
if (*aug == 'z') |
597 |
{ |
{ |
598 |
aug++; |
aug++; |
599 |
read_uleb128 (cie.augmentation_size, buf); |
REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size)); |
600 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
601 |
} |
} |
602 |
|
|
604 |
switch (*aug++) |
switch (*aug++) |
605 |
{ |
{ |
606 |
case 'L': |
case 'L': |
607 |
cie.lsda_encoding = *buf++; |
REQUIRE (read_byte (&buf, end, &cie.lsda_encoding)); |
608 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
609 |
if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) |
REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size)); |
|
goto free_no_table; |
|
610 |
break; |
break; |
611 |
case 'R': |
case 'R': |
612 |
cie.fde_encoding = *buf++; |
REQUIRE (read_byte (&buf, end, &cie.fde_encoding)); |
613 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
614 |
if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) |
REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size)); |
|
goto free_no_table; |
|
615 |
break; |
break; |
616 |
case 'P': |
case 'P': |
617 |
{ |
{ |
618 |
int per_width; |
int per_width; |
619 |
|
|
620 |
cie.per_encoding = *buf++; |
REQUIRE (read_byte (&buf, end, &cie.per_encoding)); |
621 |
per_width = get_DW_EH_PE_width (cie.per_encoding, |
per_width = get_DW_EH_PE_width (cie.per_encoding, |
622 |
ptr_size); |
ptr_size); |
623 |
if (per_width == 0) |
REQUIRE (per_width); |
|
goto free_no_table; |
|
624 |
if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) |
if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) |
625 |
buf = (ehbuf |
{ |
626 |
+ ((buf - ehbuf + per_width - 1) |
length = -(buf - ehbuf) & (per_width - 1); |
627 |
& ~((bfd_size_type) per_width - 1))); |
REQUIRE (skip_bytes (&buf, end, length)); |
628 |
|
} |
629 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
|
rel = GET_RELOC (buf); |
|
630 |
/* Ensure we have a reloc here, against |
/* Ensure we have a reloc here, against |
631 |
a global symbol. */ |
a global symbol. */ |
632 |
if (rel != NULL) |
if (GET_RELOC (buf) != NULL) |
633 |
{ |
{ |
634 |
unsigned long r_symndx; |
unsigned long r_symndx; |
635 |
|
|
653 |
|
|
654 |
cie.personality = h; |
cie.personality = h; |
655 |
} |
} |
656 |
cookie->rel++; |
/* Cope with MIPS-style composite relocations. */ |
657 |
|
do |
658 |
|
cookie->rel++; |
659 |
|
while (GET_RELOC (buf) != NULL); |
660 |
} |
} |
661 |
buf += per_width; |
REQUIRE (skip_bytes (&buf, end, per_width)); |
662 |
} |
} |
663 |
break; |
break; |
664 |
default: |
default: |
669 |
|
|
670 |
/* For shared libraries, try to get rid of as many RELATIVE relocs |
/* For shared libraries, try to get rid of as many RELATIVE relocs |
671 |
as possible. */ |
as possible. */ |
672 |
if (info->shared |
if (info->shared |
673 |
&& (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) |
&& (get_elf_backend_data (abfd) |
674 |
cie.make_relative = 1; |
->elf_backend_can_make_relative_eh_frame |
675 |
|
(abfd, info, sec))) |
676 |
|
{ |
677 |
|
if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) |
678 |
|
cie.make_relative = 1; |
679 |
|
/* If the CIE doesn't already have an 'R' entry, it's fairly |
680 |
|
easy to add one, provided that there's no aligned data |
681 |
|
after the augmentation string. */ |
682 |
|
else if (cie.fde_encoding == DW_EH_PE_omit |
683 |
|
&& (cie.per_encoding & 0xf0) != DW_EH_PE_aligned) |
684 |
|
{ |
685 |
|
if (*cie.augmentation == 0) |
686 |
|
this_inf->add_augmentation_size = 1; |
687 |
|
this_inf->add_fde_encoding = 1; |
688 |
|
cie.make_relative = 1; |
689 |
|
} |
690 |
|
} |
691 |
|
|
692 |
if (info->shared |
if (info->shared |
693 |
|
&& (get_elf_backend_data (abfd) |
694 |
|
->elf_backend_can_make_lsda_relative_eh_frame |
695 |
|
(abfd, info, sec)) |
696 |
&& (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) |
&& (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) |
697 |
cie.make_lsda_relative = 1; |
cie.make_lsda_relative = 1; |
698 |
|
|
701 |
if (cie.fde_encoding == DW_EH_PE_omit) |
if (cie.fde_encoding == DW_EH_PE_omit) |
702 |
cie.fde_encoding = DW_EH_PE_absptr; |
cie.fde_encoding = DW_EH_PE_absptr; |
703 |
|
|
704 |
initial_insn_length = cie.hdr.length - (buf - last_fde - 4); |
initial_insn_length = end - buf; |
705 |
if (initial_insn_length <= 50) |
if (initial_insn_length <= 50) |
706 |
{ |
{ |
707 |
cie.initial_insn_length = initial_insn_length; |
cie.initial_insn_length = initial_insn_length; |
708 |
memcpy (cie.initial_instructions, buf, initial_insn_length); |
memcpy (cie.initial_instructions, buf, initial_insn_length); |
709 |
} |
} |
710 |
|
insns = buf; |
711 |
buf += initial_insn_length; |
buf += initial_insn_length; |
712 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
713 |
last_cie = last_fde; |
last_cie = last_fde; |
715 |
else |
else |
716 |
{ |
{ |
717 |
/* Ensure this FDE uses the last CIE encountered. */ |
/* Ensure this FDE uses the last CIE encountered. */ |
718 |
if (last_cie == NULL |
REQUIRE (last_cie); |
719 |
|| hdr.id != (unsigned int) (buf - 4 - last_cie)) |
REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie)); |
|
goto free_no_table; |
|
720 |
|
|
721 |
ENSURE_NO_RELOCS (buf); |
ENSURE_NO_RELOCS (buf); |
722 |
rel = GET_RELOC (buf); |
REQUIRE (GET_RELOC (buf)); |
723 |
if (rel == NULL) |
|
|
/* This should not happen. */ |
|
|
goto free_no_table; |
|
724 |
if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) |
if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) |
725 |
{ |
/* This is a FDE against a discarded section. It should |
726 |
cookie->rel = rel; |
be deleted. */ |
727 |
/* This is a FDE against discarded section, it should |
this_inf->removed = 1; |
|
be deleted. */ |
|
|
new_size -= hdr.length + 4; |
|
|
sec_info->entry[sec_info->count].removed = 1; |
|
|
} |
|
728 |
else |
else |
729 |
{ |
{ |
730 |
if (info->shared |
if (info->shared |
732 |
&& cie.make_relative == 0) |
&& cie.make_relative == 0) |
733 |
|| (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) |
|| (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) |
734 |
{ |
{ |
735 |
/* If shared library uses absolute pointers |
/* If a shared library uses absolute pointers |
736 |
which we cannot turn into PC relative, |
which we cannot turn into PC relative, |
737 |
don't create the binary search table, |
don't create the binary search table, |
738 |
since it is affected by runtime relocations. */ |
since it is affected by runtime relocations. */ |
739 |
hdr_info->table = false; |
hdr_info->table = FALSE; |
740 |
} |
} |
741 |
cie_usage_count++; |
cie_usage_count++; |
742 |
hdr_info->fde_count++; |
hdr_info->fde_count++; |
743 |
} |
} |
744 |
cookie->rel = rel; |
/* Skip the initial location and address range. */ |
745 |
|
start = buf; |
746 |
|
length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); |
747 |
|
REQUIRE (skip_bytes (&buf, end, 2 * length)); |
748 |
|
|
749 |
|
/* Skip the augmentation size, if present. */ |
750 |
|
if (cie.augmentation[0] == 'z') |
751 |
|
REQUIRE (read_uleb128 (&buf, end, &length)); |
752 |
|
else |
753 |
|
length = 0; |
754 |
|
|
755 |
|
/* Of the supported augmentation characters above, only 'L' |
756 |
|
adds augmentation data to the FDE. This code would need to |
757 |
|
be adjusted if any future augmentations do the same thing. */ |
758 |
if (cie.lsda_encoding != DW_EH_PE_omit) |
if (cie.lsda_encoding != DW_EH_PE_omit) |
759 |
{ |
{ |
760 |
unsigned int dummy; |
this_inf->lsda_offset = buf - start; |
761 |
|
/* If there's no 'z' augmentation, we don't know where the |
762 |
aug = buf; |
CFA insns begin. Assume no padding. */ |
763 |
buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); |
if (cie.augmentation[0] != 'z') |
764 |
if (cie.augmentation[0] == 'z') |
length = end - buf; |
|
read_uleb128 (dummy, buf); |
|
|
/* If some new augmentation data is added before LSDA |
|
|
in FDE augmentation area, this need to be adjusted. */ |
|
|
sec_info->entry[sec_info->count].lsda_offset = (buf - aug); |
|
765 |
} |
} |
766 |
|
|
767 |
|
/* Skip over the augmentation data. */ |
768 |
|
REQUIRE (skip_bytes (&buf, end, length)); |
769 |
|
insns = buf; |
770 |
|
|
771 |
buf = last_fde + 4 + hdr.length; |
buf = last_fde + 4 + hdr.length; |
772 |
SKIP_RELOCS (buf); |
SKIP_RELOCS (buf); |
773 |
} |
} |
774 |
|
|
775 |
sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; |
/* Try to interpret the CFA instructions and find the first |
776 |
sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; |
padding nop. Shrink this_inf's size so that it doesn't |
777 |
|
including the padding. */ |
778 |
|
length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); |
779 |
|
insns = skip_non_nops (insns, end, length); |
780 |
|
if (insns != 0) |
781 |
|
this_inf->size -= end - insns; |
782 |
|
|
783 |
|
this_inf->fde_encoding = cie.fde_encoding; |
784 |
|
this_inf->lsda_encoding = cie.lsda_encoding; |
785 |
sec_info->count++; |
sec_info->count++; |
786 |
} |
} |
787 |
|
|
788 |
elf_section_data (sec)->sec_info = sec_info; |
elf_section_data (sec)->sec_info = sec_info; |
789 |
elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME; |
sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; |
790 |
|
|
791 |
/* Ok, now we can assign new offsets. */ |
/* Ok, now we can assign new offsets. */ |
792 |
offset = 0; |
offset = 0; |
793 |
last_cie_ndx = 0; |
last_cie_inf = hdr_info->last_cie_inf; |
794 |
for (i = 0; i < sec_info->count; i++) |
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
795 |
{ |
if (!ent->removed) |
796 |
if (! sec_info->entry[i].removed) |
{ |
797 |
{ |
if (ent->cie) |
798 |
sec_info->entry[i].new_offset = offset; |
last_cie_inf = ent; |
799 |
offset += sec_info->entry[i].size; |
else |
800 |
if (sec_info->entry[i].cie) |
ent->cie_inf = last_cie_inf; |
801 |
{ |
ent->new_offset = offset; |
802 |
last_cie_ndx = i; |
offset += size_of_output_cie_fde (ent, ptr_size); |
803 |
make_relative = sec_info->entry[i].make_relative; |
} |
804 |
make_lsda_relative = sec_info->entry[i].make_lsda_relative; |
hdr_info->last_cie_inf = last_cie_inf; |
|
} |
|
|
else |
|
|
{ |
|
|
sec_info->entry[i].make_relative = make_relative; |
|
|
sec_info->entry[i].make_lsda_relative = make_lsda_relative; |
|
|
sec_info->entry[i].per_encoding_relative = 0; |
|
|
} |
|
|
} |
|
|
else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) |
|
|
{ |
|
|
/* Need to adjust new_offset too. */ |
|
|
BFD_ASSERT (sec_info->entry[last_cie_ndx].offset |
|
|
== sec_info->entry[i].new_offset); |
|
|
sec_info->entry[i].new_offset |
|
|
= sec_info->entry[last_cie_ndx].new_offset; |
|
|
} |
|
|
} |
|
|
if (hdr_info->last_cie_sec == sec) |
|
|
{ |
|
|
BFD_ASSERT (sec_info->entry[last_cie_ndx].offset |
|
|
== hdr_info->last_cie_offset); |
|
|
hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; |
|
|
} |
|
|
|
|
|
/* FIXME: Currently it is not possible to shrink sections to zero size at |
|
|
this point, so build a fake minimal CIE. */ |
|
|
if (new_size == 0) |
|
|
new_size = 16; |
|
805 |
|
|
806 |
/* Shrink the sec as needed. */ |
/* Resize the sec as needed. */ |
807 |
sec->_cooked_size = new_size; |
sec->rawsize = sec->size; |
808 |
if (sec->_cooked_size == 0) |
sec->size = offset; |
809 |
|
if (sec->size == 0) |
810 |
sec->flags |= SEC_EXCLUDE; |
sec->flags |= SEC_EXCLUDE; |
811 |
|
|
812 |
free (ehbuf); |
free (ehbuf); |
813 |
return new_size != sec->_raw_size; |
return offset != sec->rawsize; |
814 |
|
|
815 |
free_no_table: |
free_no_table: |
816 |
if (ehbuf) |
if (ehbuf) |
817 |
free (ehbuf); |
free (ehbuf); |
818 |
if (sec_info) |
if (sec_info) |
819 |
free (sec_info); |
free (sec_info); |
820 |
hdr_info->table = false; |
hdr_info->table = FALSE; |
821 |
hdr_info->last_cie.hdr.length = 0; |
hdr_info->last_cie.hdr.length = 0; |
822 |
return false; |
return FALSE; |
823 |
|
|
824 |
|
#undef REQUIRE |
825 |
} |
} |
826 |
|
|
827 |
/* This function is called for .eh_frame_hdr section after |
/* This function is called for .eh_frame_hdr section after |
828 |
_bfd_elf_discard_section_eh_frame has been called on all .eh_frame |
_bfd_elf_discard_section_eh_frame has been called on all .eh_frame |
829 |
input sections. It finalizes the size of .eh_frame_hdr section. */ |
input sections. It finalizes the size of .eh_frame_hdr section. */ |
830 |
|
|
831 |
boolean |
bfd_boolean |
832 |
_bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec) |
_bfd_elf_discard_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
|
bfd *abfd; |
|
|
struct bfd_link_info *info; |
|
|
asection *sec; |
|
833 |
{ |
{ |
834 |
|
struct elf_link_hash_table *htab; |
835 |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_hdr_info *hdr_info; |
836 |
unsigned int ptr_size; |
asection *sec; |
837 |
|
|
838 |
ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] |
htab = elf_hash_table (info); |
839 |
== ELFCLASS64) ? 8 : 4; |
hdr_info = &htab->eh_info; |
840 |
|
sec = hdr_info->hdr_sec; |
841 |
|
if (sec == NULL) |
842 |
|
return FALSE; |
843 |
|
|
844 |
if ((elf_section_data (sec)->sec_info_type |
sec->size = EH_FRAME_HDR_SIZE; |
|
!= ELF_INFO_TYPE_EH_FRAME_HDR) |
|
|
|| ! info->eh_frame_hdr) |
|
|
{ |
|
|
_bfd_strip_section_from_output (info, sec); |
|
|
return false; |
|
|
} |
|
|
|
|
|
hdr_info = (struct eh_frame_hdr_info *) |
|
|
elf_section_data (sec)->sec_info; |
|
|
if (hdr_info->strip) |
|
|
return false; |
|
|
sec->_cooked_size = EH_FRAME_HDR_SIZE; |
|
845 |
if (hdr_info->table) |
if (hdr_info->table) |
846 |
sec->_cooked_size += 4 + hdr_info->fde_count * 8; |
sec->size += 4 + hdr_info->fde_count * 8; |
847 |
|
|
848 |
/* Request program headers to be recalculated. */ |
/* Request program headers to be recalculated. */ |
849 |
elf_tdata (abfd)->program_header_size = 0; |
elf_tdata (abfd)->program_header_size = 0; |
850 |
elf_tdata (abfd)->eh_frame_hdr = true; |
elf_tdata (abfd)->eh_frame_hdr = sec; |
851 |
return true; |
return TRUE; |
852 |
} |
} |
853 |
|
|
854 |
/* This function is called from size_dynamic_sections. |
/* This function is called from size_dynamic_sections. |
856 |
because later on it is too late for calling _bfd_strip_section_from_output, |
because later on it is too late for calling _bfd_strip_section_from_output, |
857 |
since dynamic symbol table has been sized. */ |
since dynamic symbol table has been sized. */ |
858 |
|
|
859 |
boolean |
bfd_boolean |
860 |
_bfd_elf_maybe_strip_eh_frame_hdr (info) |
_bfd_elf_maybe_strip_eh_frame_hdr (struct bfd_link_info *info) |
|
struct bfd_link_info *info; |
|
861 |
{ |
{ |
862 |
asection *sec, *o; |
asection *o; |
863 |
bfd *abfd; |
bfd *abfd; |
864 |
|
struct elf_link_hash_table *htab; |
865 |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_hdr_info *hdr_info; |
866 |
|
|
867 |
sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr"); |
htab = elf_hash_table (info); |
868 |
if (sec == NULL || bfd_is_abs_section (sec->output_section)) |
hdr_info = &htab->eh_info; |
869 |
return true; |
if (hdr_info->hdr_sec == NULL) |
870 |
|
return TRUE; |
|
hdr_info |
|
|
= bfd_zmalloc (sizeof (struct eh_frame_hdr_info)); |
|
|
if (hdr_info == NULL) |
|
|
return false; |
|
871 |
|
|
872 |
elf_section_data (sec)->sec_info = hdr_info; |
if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)) |
873 |
elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR; |
{ |
874 |
|
hdr_info->hdr_sec = NULL; |
875 |
|
return TRUE; |
876 |
|
} |
877 |
|
|
878 |
abfd = NULL; |
abfd = NULL; |
879 |
if (info->eh_frame_hdr) |
if (info->eh_frame_hdr) |
882 |
/* Count only sections which have at least a single CIE or FDE. |
/* Count only sections which have at least a single CIE or FDE. |
883 |
There cannot be any CIE or FDE <= 8 bytes. */ |
There cannot be any CIE or FDE <= 8 bytes. */ |
884 |
o = bfd_get_section_by_name (abfd, ".eh_frame"); |
o = bfd_get_section_by_name (abfd, ".eh_frame"); |
885 |
if (o && o->_raw_size > 8 && !bfd_is_abs_section (o->output_section)) |
if (o && o->size > 8 && !bfd_is_abs_section (o->output_section)) |
886 |
break; |
break; |
887 |
} |
} |
888 |
|
|
889 |
if (abfd == NULL) |
if (abfd == NULL) |
890 |
{ |
{ |
891 |
_bfd_strip_section_from_output (info, sec); |
_bfd_strip_section_from_output (info, hdr_info->hdr_sec); |
892 |
hdr_info->strip = true; |
hdr_info->hdr_sec = NULL; |
893 |
|
return TRUE; |
894 |
} |
} |
895 |
else |
|
896 |
hdr_info->table = true; |
hdr_info->table = TRUE; |
897 |
return true; |
return TRUE; |
898 |
} |
} |
899 |
|
|
900 |
/* Adjust an address in the .eh_frame section. Given OFFSET within |
/* Adjust an address in the .eh_frame section. Given OFFSET within |
903 |
or to offset with dynamic relocation which is no longer needed. */ |
or to offset with dynamic relocation which is no longer needed. */ |
904 |
|
|
905 |
bfd_vma |
bfd_vma |
906 |
_bfd_elf_eh_frame_section_offset (output_bfd, sec, offset) |
_bfd_elf_eh_frame_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, |
907 |
bfd *output_bfd ATTRIBUTE_UNUSED; |
struct bfd_link_info *info, |
908 |
asection *sec; |
asection *sec, |
909 |
bfd_vma offset; |
bfd_vma offset) |
910 |
{ |
{ |
911 |
struct eh_frame_sec_info *sec_info; |
struct eh_frame_sec_info *sec_info; |
912 |
|
struct elf_link_hash_table *htab; |
913 |
|
struct eh_frame_hdr_info *hdr_info; |
914 |
unsigned int lo, hi, mid; |
unsigned int lo, hi, mid; |
915 |
|
|
916 |
if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME) |
if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) |
917 |
return offset; |
return offset; |
918 |
sec_info = (struct eh_frame_sec_info *) |
sec_info = elf_section_data (sec)->sec_info; |
919 |
elf_section_data (sec)->sec_info; |
|
920 |
|
if (offset >= sec->rawsize) |
921 |
|
return offset - sec->rawsize + sec->size; |
922 |
|
|
923 |
if (offset >= sec->_raw_size) |
htab = elf_hash_table (info); |
924 |
return offset - (sec->_cooked_size - sec->_raw_size); |
hdr_info = &htab->eh_info; |
925 |
|
if (hdr_info->offsets_adjusted) |
926 |
|
offset += sec->output_offset; |
927 |
|
|
928 |
lo = 0; |
lo = 0; |
929 |
hi = sec_info->count; |
hi = sec_info->count; |
948 |
|
|
949 |
/* If converting to DW_EH_PE_pcrel, there will be no need for run-time |
/* If converting to DW_EH_PE_pcrel, there will be no need for run-time |
950 |
relocation against FDE's initial_location field. */ |
relocation against FDE's initial_location field. */ |
951 |
if (sec_info->entry[mid].make_relative |
if (!sec_info->entry[mid].cie |
952 |
&& ! sec_info->entry[mid].cie |
&& sec_info->entry[mid].cie_inf->make_relative |
953 |
&& offset == sec_info->entry[mid].offset + 8) |
&& offset == sec_info->entry[mid].offset + 8) |
954 |
return (bfd_vma) -2; |
return (bfd_vma) -2; |
955 |
|
|
956 |
/* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need |
/* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need |
957 |
for run-time relocation against LSDA field. */ |
for run-time relocation against LSDA field. */ |
958 |
if (sec_info->entry[mid].make_lsda_relative |
if (!sec_info->entry[mid].cie |
959 |
&& ! sec_info->entry[mid].cie |
&& sec_info->entry[mid].cie_inf->make_lsda_relative |
960 |
&& (offset |
&& (offset == (sec_info->entry[mid].offset + 8 |
961 |
== (sec_info->entry[mid].offset + 8 |
+ sec_info->entry[mid].lsda_offset)) |
962 |
+ sec_info->entry[mid].lsda_offset))) |
&& (sec_info->entry[mid].cie_inf->need_lsda_relative |
963 |
return (bfd_vma) -2; |
|| !hdr_info->offsets_adjusted)) |
964 |
|
{ |
965 |
|
sec_info->entry[mid].cie_inf->need_lsda_relative = 1; |
966 |
|
return (bfd_vma) -2; |
967 |
|
} |
968 |
|
|
969 |
|
if (hdr_info->offsets_adjusted) |
970 |
|
offset -= sec->output_offset; |
971 |
|
/* Any new augmentation bytes go before the first relocation. */ |
972 |
return (offset + sec_info->entry[mid].new_offset |
return (offset + sec_info->entry[mid].new_offset |
973 |
- sec_info->entry[mid].offset); |
- sec_info->entry[mid].offset |
974 |
|
+ extra_augmentation_string_bytes (sec_info->entry + mid) |
975 |
|
+ extra_augmentation_data_bytes (sec_info->entry + mid)); |
976 |
} |
} |
977 |
|
|
978 |
/* Write out .eh_frame section. This is called with the relocated |
/* Write out .eh_frame section. This is called with the relocated |
979 |
contents. */ |
contents. */ |
980 |
|
|
981 |
boolean |
bfd_boolean |
982 |
_bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents) |
_bfd_elf_write_section_eh_frame (bfd *abfd, |
983 |
bfd *abfd; |
struct bfd_link_info *info, |
984 |
asection *sec, *ehdrsec; |
asection *sec, |
985 |
bfd_byte *contents; |
bfd_byte *contents) |
986 |
{ |
{ |
987 |
struct eh_frame_sec_info *sec_info; |
struct eh_frame_sec_info *sec_info; |
988 |
|
struct elf_link_hash_table *htab; |
989 |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_hdr_info *hdr_info; |
|
unsigned int i; |
|
|
bfd_byte *p, *buf; |
|
|
unsigned int leb128_tmp; |
|
|
unsigned int cie_offset = 0; |
|
990 |
unsigned int ptr_size; |
unsigned int ptr_size; |
991 |
|
struct eh_cie_fde *ent; |
992 |
|
|
993 |
ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS] |
if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) |
994 |
== ELFCLASS64) ? 8 : 4; |
return bfd_set_section_contents (abfd, sec->output_section, contents, |
995 |
|
sec->output_offset, sec->size); |
996 |
|
|
997 |
|
ptr_size = (get_elf_backend_data (abfd) |
998 |
|
->elf_backend_eh_frame_address_size (abfd, sec)); |
999 |
|
BFD_ASSERT (ptr_size != 0); |
1000 |
|
|
1001 |
|
sec_info = elf_section_data (sec)->sec_info; |
1002 |
|
htab = elf_hash_table (info); |
1003 |
|
hdr_info = &htab->eh_info; |
1004 |
|
|
1005 |
|
/* First convert all offsets to output section offsets, so that a |
1006 |
|
CIE offset is valid if the CIE is used by a FDE from some other |
1007 |
|
section. This can happen when duplicate CIEs are deleted in |
1008 |
|
_bfd_elf_discard_section_eh_frame. We do all sections here because |
1009 |
|
this function might not be called on sections in the same order as |
1010 |
|
_bfd_elf_discard_section_eh_frame. */ |
1011 |
|
if (!hdr_info->offsets_adjusted) |
1012 |
|
{ |
1013 |
|
bfd *ibfd; |
1014 |
|
asection *eh; |
1015 |
|
struct eh_frame_sec_info *eh_inf; |
1016 |
|
|
1017 |
|
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) |
1018 |
|
{ |
1019 |
|
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour |
1020 |
|
|| (ibfd->flags & DYNAMIC) != 0) |
1021 |
|
continue; |
1022 |
|
|
1023 |
|
eh = bfd_get_section_by_name (ibfd, ".eh_frame"); |
1024 |
|
if (eh == NULL || eh->sec_info_type != ELF_INFO_TYPE_EH_FRAME) |
1025 |
|
continue; |
1026 |
|
|
1027 |
if (elf_section_data (sec)->sec_info_type != ELF_INFO_TYPE_EH_FRAME) |
eh_inf = elf_section_data (eh)->sec_info; |
1028 |
return bfd_set_section_contents (abfd, sec->output_section, |
for (ent = eh_inf->entry; ent < eh_inf->entry + eh_inf->count; ++ent) |
1029 |
contents, |
{ |
1030 |
(file_ptr) sec->output_offset, |
ent->offset += eh->output_offset; |
1031 |
sec->_raw_size); |
ent->new_offset += eh->output_offset; |
1032 |
sec_info = (struct eh_frame_sec_info *) |
} |
1033 |
elf_section_data (sec)->sec_info; |
} |
1034 |
hdr_info = NULL; |
hdr_info->offsets_adjusted = TRUE; |
|
if (ehdrsec |
|
|
&& (elf_section_data (ehdrsec)->sec_info_type |
|
|
== ELF_INFO_TYPE_EH_FRAME_HDR)) |
|
|
{ |
|
|
hdr_info = (struct eh_frame_hdr_info *) |
|
|
elf_section_data (ehdrsec)->sec_info; |
|
|
if (hdr_info->table && hdr_info->array == NULL) |
|
|
hdr_info->array |
|
|
= bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); |
|
|
if (hdr_info->array == NULL) |
|
|
hdr_info = NULL; |
|
1035 |
} |
} |
1036 |
|
|
1037 |
p = contents; |
if (hdr_info->table && hdr_info->array == NULL) |
1038 |
for (i = 0; i < sec_info->count; ++i) |
hdr_info->array |
1039 |
|
= bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); |
1040 |
|
if (hdr_info->array == NULL) |
1041 |
|
hdr_info = NULL; |
1042 |
|
|
1043 |
|
/* The new offsets can be bigger or smaller than the original offsets. |
1044 |
|
We therefore need to make two passes over the section: one backward |
1045 |
|
pass to move entries up and one forward pass to move entries down. |
1046 |
|
The two passes won't interfere with each other because entries are |
1047 |
|
not reordered */ |
1048 |
|
for (ent = sec_info->entry + sec_info->count; ent-- != sec_info->entry;) |
1049 |
|
if (!ent->removed && ent->new_offset > ent->offset) |
1050 |
|
memmove (contents + ent->new_offset - sec->output_offset, |
1051 |
|
contents + ent->offset - sec->output_offset, ent->size); |
1052 |
|
|
1053 |
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
1054 |
|
if (!ent->removed && ent->new_offset < ent->offset) |
1055 |
|
memmove (contents + ent->new_offset - sec->output_offset, |
1056 |
|
contents + ent->offset - sec->output_offset, ent->size); |
1057 |
|
|
1058 |
|
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) |
1059 |
{ |
{ |
1060 |
if (sec_info->entry[i].removed) |
unsigned char *buf, *end; |
1061 |
|
unsigned int new_size; |
1062 |
|
|
1063 |
|
if (ent->removed) |
1064 |
|
continue; |
1065 |
|
|
1066 |
|
if (ent->size == 4) |
1067 |
{ |
{ |
1068 |
if (sec_info->entry[i].cie) |
/* Any terminating FDE must be at the end of the section. */ |
1069 |
{ |
BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1); |
|
/* If CIE is removed due to no remaining FDEs referencing it |
|
|
and there were no CIEs kept before it, sec_info->entry[i].sec |
|
|
will be zero. */ |
|
|
if (sec_info->entry[i].sec == NULL) |
|
|
cie_offset = 0; |
|
|
else |
|
|
{ |
|
|
cie_offset = sec_info->entry[i].new_offset; |
|
|
cie_offset += (sec_info->entry[i].sec->output_section->vma |
|
|
+ sec_info->entry[i].sec->output_offset |
|
|
- sec->output_section->vma |
|
|
- sec->output_offset); |
|
|
} |
|
|
} |
|
1070 |
continue; |
continue; |
1071 |
} |
} |
1072 |
|
|
1073 |
if (sec_info->entry[i].cie) |
buf = contents + ent->new_offset - sec->output_offset; |
1074 |
|
end = buf + ent->size; |
1075 |
|
new_size = size_of_output_cie_fde (ent, ptr_size); |
1076 |
|
|
1077 |
|
/* Install the new size, filling the extra bytes with DW_CFA_nops. */ |
1078 |
|
if (new_size != ent->size) |
1079 |
|
{ |
1080 |
|
memset (end, 0, new_size - ent->size); |
1081 |
|
bfd_put_32 (abfd, new_size - 4, buf); |
1082 |
|
} |
1083 |
|
|
1084 |
|
if (ent->cie) |
1085 |
{ |
{ |
1086 |
/* CIE */ |
/* CIE */ |
1087 |
cie_offset = sec_info->entry[i].new_offset; |
if (ent->make_relative |
1088 |
if (sec_info->entry[i].make_relative |
|| ent->need_lsda_relative |
1089 |
|| sec_info->entry[i].make_lsda_relative |
|| ent->per_encoding_relative) |
|
|| sec_info->entry[i].per_encoding_relative) |
|
1090 |
{ |
{ |
1091 |
unsigned char *aug; |
char *aug; |
1092 |
unsigned int action; |
unsigned int action, extra_string, extra_data; |
1093 |
unsigned int dummy, per_width, per_encoding; |
unsigned int per_width, per_encoding; |
1094 |
|
|
1095 |
/* Need to find 'R' or 'L' augmentation's argument and modify |
/* Need to find 'R' or 'L' augmentation's argument and modify |
1096 |
DW_EH_PE_* value. */ |
DW_EH_PE_* value. */ |
1097 |
action = (sec_info->entry[i].make_relative ? 1 : 0) |
action = ((ent->make_relative ? 1 : 0) |
1098 |
| (sec_info->entry[i].make_lsda_relative ? 2 : 0) |
| (ent->need_lsda_relative ? 2 : 0) |
1099 |
| (sec_info->entry[i].per_encoding_relative ? 4 : 0); |
| (ent->per_encoding_relative ? 4 : 0)); |
1100 |
buf = contents + sec_info->entry[i].offset; |
extra_string = extra_augmentation_string_bytes (ent); |
1101 |
|
extra_data = extra_augmentation_data_bytes (ent); |
1102 |
|
|
1103 |
/* Skip length, id and version. */ |
/* Skip length, id and version. */ |
1104 |
buf += 9; |
buf += 9; |
1105 |
aug = buf; |
aug = (char *) buf; |
1106 |
buf = strchr (buf, '\0') + 1; |
buf += strlen (aug) + 1; |
1107 |
read_uleb128 (dummy, buf); |
skip_leb128 (&buf, end); |
1108 |
read_sleb128 (dummy, buf); |
skip_leb128 (&buf, end); |
1109 |
read_uleb128 (dummy, buf); |
skip_leb128 (&buf, end); |
1110 |
if (*aug == 'z') |
if (*aug == 'z') |
1111 |
{ |
{ |
1112 |
read_uleb128 (dummy, buf); |
/* The uleb128 will always be a single byte for the kind |
1113 |
|
of augmentation strings that we're prepared to handle. */ |
1114 |
|
*buf++ += extra_data; |
1115 |
aug++; |
aug++; |
1116 |
} |
} |
1117 |
|
|
1118 |
|
/* Make room for the new augmentation string and data bytes. */ |
1119 |
|
memmove (buf + extra_string + extra_data, buf, end - buf); |
1120 |
|
memmove (aug + extra_string, aug, buf - (bfd_byte *) aug); |
1121 |
|
buf += extra_string; |
1122 |
|
end += extra_string + extra_data; |
1123 |
|
|
1124 |
|
if (ent->add_augmentation_size) |
1125 |
|
{ |
1126 |
|
*aug++ = 'z'; |
1127 |
|
*buf++ = extra_data - 1; |
1128 |
|
} |
1129 |
|
if (ent->add_fde_encoding) |
1130 |
|
{ |
1131 |
|
BFD_ASSERT (action & 1); |
1132 |
|
*aug++ = 'R'; |
1133 |
|
*buf++ = DW_EH_PE_pcrel; |
1134 |
|
action &= ~1; |
1135 |
|
} |
1136 |
|
|
1137 |
while (action) |
while (action) |
1138 |
switch (*aug++) |
switch (*aug++) |
1139 |
{ |
{ |
1140 |
case 'L': |
case 'L': |
1141 |
if (action & 2) |
if (action & 2) |
1142 |
{ |
{ |
1143 |
BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding); |
BFD_ASSERT (*buf == ent->lsda_encoding); |
1144 |
*buf |= DW_EH_PE_pcrel; |
*buf |= DW_EH_PE_pcrel; |
1145 |
action &= ~2; |
action &= ~2; |
1146 |
} |
} |
1148 |
break; |
break; |
1149 |
case 'P': |
case 'P': |
1150 |
per_encoding = *buf++; |
per_encoding = *buf++; |
1151 |
per_width = get_DW_EH_PE_width (per_encoding, |
per_width = get_DW_EH_PE_width (per_encoding, ptr_size); |
|
ptr_size); |
|
1152 |
BFD_ASSERT (per_width != 0); |
BFD_ASSERT (per_width != 0); |
1153 |
BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel) |
BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel) |
1154 |
== sec_info->entry[i].per_encoding_relative); |
== ent->per_encoding_relative); |
1155 |
if ((per_encoding & 0xf0) == DW_EH_PE_aligned) |
if ((per_encoding & 0xf0) == DW_EH_PE_aligned) |
1156 |
buf = (contents |
buf = (contents |
1157 |
+ ((buf - contents + per_width - 1) |
+ ((buf - contents + per_width - 1) |
1158 |
& ~((bfd_size_type) per_width - 1))); |
& ~((bfd_size_type) per_width - 1))); |
1159 |
if (action & 4) |
if (action & 4) |
1160 |
{ |
{ |
1161 |
bfd_vma value; |
bfd_vma val; |
1162 |
|
|
1163 |
value = read_value (abfd, buf, per_width); |
val = read_value (abfd, buf, per_width, |
1164 |
value += (sec_info->entry[i].offset |
get_DW_EH_PE_signed (per_encoding)); |
1165 |
- sec_info->entry[i].new_offset); |
val += ent->offset - ent->new_offset; |
1166 |
write_value (abfd, buf, value, per_width); |
val -= extra_string + extra_data; |
1167 |
|
write_value (abfd, buf, val, per_width); |
1168 |
action &= ~4; |
action &= ~4; |
1169 |
} |
} |
1170 |
buf += per_width; |
buf += per_width; |
1172 |
case 'R': |
case 'R': |
1173 |
if (action & 1) |
if (action & 1) |
1174 |
{ |
{ |
1175 |
BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding); |
BFD_ASSERT (*buf == ent->fde_encoding); |
1176 |
*buf |= DW_EH_PE_pcrel; |
*buf |= DW_EH_PE_pcrel; |
1177 |
action &= ~1; |
action &= ~1; |
1178 |
} |
} |
1183 |
} |
} |
1184 |
} |
} |
1185 |
} |
} |
1186 |
else if (sec_info->entry[i].size > 4) |
else |
1187 |
{ |
{ |
1188 |
/* FDE */ |
/* FDE */ |
1189 |
bfd_vma value = 0, address; |
bfd_vma value, address; |
1190 |
unsigned int width; |
unsigned int width; |
1191 |
|
|
1192 |
buf = contents + sec_info->entry[i].offset; |
/* Skip length. */ |
|
/* Skip length. */ |
|
1193 |
buf += 4; |
buf += 4; |
1194 |
bfd_put_32 (abfd, |
value = ent->new_offset + 4 - ent->cie_inf->new_offset; |
1195 |
sec_info->entry[i].new_offset + 4 - cie_offset, buf); |
bfd_put_32 (abfd, value, buf); |
1196 |
buf += 4; |
buf += 4; |
1197 |
width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, |
width = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); |
1198 |
ptr_size); |
value = read_value (abfd, buf, width, |
1199 |
address = value = read_value (abfd, buf, width); |
get_DW_EH_PE_signed (ent->fde_encoding)); |
1200 |
|
address = value; |
1201 |
if (value) |
if (value) |
1202 |
{ |
{ |
1203 |
switch (sec_info->entry[i].fde_encoding & 0xf0) |
switch (ent->fde_encoding & 0xf0) |
1204 |
{ |
{ |
1205 |
case DW_EH_PE_indirect: |
case DW_EH_PE_indirect: |
1206 |
case DW_EH_PE_textrel: |
case DW_EH_PE_textrel: |
1215 |
} |
} |
1216 |
break; |
break; |
1217 |
case DW_EH_PE_pcrel: |
case DW_EH_PE_pcrel: |
1218 |
value += (sec_info->entry[i].offset |
value += ent->offset - ent->new_offset; |
1219 |
- sec_info->entry[i].new_offset); |
address += sec->output_section->vma + ent->offset + 8; |
|
address += (sec->output_section->vma + sec->output_offset |
|
|
+ sec_info->entry[i].offset + 8); |
|
1220 |
break; |
break; |
1221 |
} |
} |
1222 |
if (sec_info->entry[i].make_relative) |
if (ent->cie_inf->make_relative) |
1223 |
value -= (sec->output_section->vma + sec->output_offset |
value -= sec->output_section->vma + ent->new_offset + 8; |
|
+ sec_info->entry[i].new_offset + 8); |
|
1224 |
write_value (abfd, buf, value, width); |
write_value (abfd, buf, value, width); |
1225 |
} |
} |
1226 |
|
|
1228 |
{ |
{ |
1229 |
hdr_info->array[hdr_info->array_count].initial_loc = address; |
hdr_info->array[hdr_info->array_count].initial_loc = address; |
1230 |
hdr_info->array[hdr_info->array_count++].fde |
hdr_info->array[hdr_info->array_count++].fde |
1231 |
= (sec->output_section->vma + sec->output_offset |
= sec->output_section->vma + ent->new_offset; |
|
+ sec_info->entry[i].new_offset); |
|
1232 |
} |
} |
1233 |
|
|
1234 |
if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel |
if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel |
1235 |
|| sec_info->entry[i].make_lsda_relative) |
|| ent->cie_inf->need_lsda_relative) |
1236 |
{ |
{ |
1237 |
buf += sec_info->entry[i].lsda_offset; |
buf += ent->lsda_offset; |
1238 |
width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding, |
width = get_DW_EH_PE_width (ent->lsda_encoding, ptr_size); |
1239 |
ptr_size); |
value = read_value (abfd, buf, width, |
1240 |
value = read_value (abfd, buf, width); |
get_DW_EH_PE_signed (ent->lsda_encoding)); |
1241 |
if (value) |
if (value) |
1242 |
{ |
{ |
1243 |
if ((sec_info->entry[i].lsda_encoding & 0xf0) |
if ((ent->lsda_encoding & 0xf0) == DW_EH_PE_pcrel) |
1244 |
== DW_EH_PE_pcrel) |
value += ent->offset - ent->new_offset; |
1245 |
value += (sec_info->entry[i].offset |
else if (ent->cie_inf->need_lsda_relative) |
1246 |
- sec_info->entry[i].new_offset); |
value -= (sec->output_section->vma + ent->new_offset + 8 |
1247 |
else if (sec_info->entry[i].make_lsda_relative) |
+ ent->lsda_offset); |
|
value -= (sec->output_section->vma + sec->output_offset |
|
|
+ sec_info->entry[i].new_offset + 8 |
|
|
+ sec_info->entry[i].lsda_offset); |
|
1248 |
write_value (abfd, buf, value, width); |
write_value (abfd, buf, value, width); |
1249 |
} |
} |
1250 |
} |
} |
1251 |
|
else if (ent->cie_inf->add_augmentation_size) |
1252 |
|
{ |
1253 |
|
/* Skip the PC and length and insert a zero byte for the |
1254 |
|
augmentation size. */ |
1255 |
|
buf += width * 2; |
1256 |
|
memmove (buf + 1, buf, end - buf); |
1257 |
|
*buf = 0; |
1258 |
|
} |
1259 |
} |
} |
|
else |
|
|
/* Terminating FDE must be at the end of .eh_frame section only. */ |
|
|
BFD_ASSERT (i == sec_info->count - 1); |
|
|
|
|
|
BFD_ASSERT (p == contents + sec_info->entry[i].new_offset); |
|
|
memmove (p, contents + sec_info->entry[i].offset, |
|
|
sec_info->entry[i].size); |
|
|
p += sec_info->entry[i].size; |
|
1260 |
} |
} |
1261 |
|
|
|
/* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to |
|
|
shrink sections to zero size, this won't be needed any more. */ |
|
|
if (p == contents && sec->_cooked_size == 16) |
|
1262 |
{ |
{ |
1263 |
bfd_put_32 (abfd, 12, p); /* Fake CIE length */ |
unsigned int alignment = 1 << sec->alignment_power; |
1264 |
bfd_put_32 (abfd, 0, p + 4); /* Fake CIE id */ |
unsigned int pad = sec->size % alignment; |
1265 |
p[8] = 1; /* Fake CIE version */ |
|
1266 |
memset (p + 9, 0, 7); /* Fake CIE augmentation, 3xleb128 |
/* Don't pad beyond the raw size of the output section. It |
1267 |
and 3xDW_CFA_nop as pad */ |
can happen at the last input section. */ |
1268 |
p += 16; |
if (pad |
1269 |
} |
&& ((sec->output_offset + sec->size + pad) |
1270 |
|
<= sec->output_section->size)) |
1271 |
|
{ |
1272 |
|
bfd_byte *buf; |
1273 |
|
unsigned int new_size; |
1274 |
|
|
1275 |
BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size); |
/* Find the last CIE/FDE. */ |
1276 |
|
ent = sec_info->entry + sec_info->count; |
1277 |
|
while (--ent != sec_info->entry) |
1278 |
|
if (!ent->removed) |
1279 |
|
break; |
1280 |
|
|
1281 |
|
/* The size of the last CIE/FDE must be at least 4. */ |
1282 |
|
if (ent->removed || ent->size < 4) |
1283 |
|
abort (); |
1284 |
|
|
1285 |
|
pad = alignment - pad; |
1286 |
|
buf = contents + ent->new_offset - sec->output_offset; |
1287 |
|
new_size = size_of_output_cie_fde (ent, ptr_size); |
1288 |
|
|
1289 |
|
/* Pad it with DW_CFA_nop */ |
1290 |
|
memset (buf + new_size, 0, pad); |
1291 |
|
bfd_put_32 (abfd, new_size + pad - 4, buf); |
1292 |
|
|
1293 |
|
sec->size += pad; |
1294 |
|
} |
1295 |
|
} |
1296 |
|
|
1297 |
return bfd_set_section_contents (abfd, sec->output_section, |
return bfd_set_section_contents (abfd, sec->output_section, |
1298 |
contents, (file_ptr) sec->output_offset, |
contents, (file_ptr) sec->output_offset, |
1299 |
sec->_cooked_size); |
sec->size); |
1300 |
} |
} |
1301 |
|
|
1302 |
/* Helper function used to sort .eh_frame_hdr search table by increasing |
/* Helper function used to sort .eh_frame_hdr search table by increasing |
1303 |
VMA of FDE initial location. */ |
VMA of FDE initial location. */ |
1304 |
|
|
1305 |
static int |
static int |
1306 |
vma_compare (a, b) |
vma_compare (const void *a, const void *b) |
|
const PTR a; |
|
|
const PTR b; |
|
1307 |
{ |
{ |
1308 |
struct eh_frame_array_ent *p = (struct eh_frame_array_ent *) a; |
const struct eh_frame_array_ent *p = a; |
1309 |
struct eh_frame_array_ent *q = (struct eh_frame_array_ent *) b; |
const struct eh_frame_array_ent *q = b; |
1310 |
if (p->initial_loc > q->initial_loc) |
if (p->initial_loc > q->initial_loc) |
1311 |
return 1; |
return 1; |
1312 |
if (p->initial_loc < q->initial_loc) |
if (p->initial_loc < q->initial_loc) |
1334 |
fde_count x [encoded] initial_loc, fde |
fde_count x [encoded] initial_loc, fde |
1335 |
(array of encoded pairs containing |
(array of encoded pairs containing |
1336 |
FDE initial_location field and FDE address, |
FDE initial_location field and FDE address, |
1337 |
sorted by increasing initial_loc) */ |
sorted by increasing initial_loc). */ |
1338 |
|
|
1339 |
boolean |
bfd_boolean |
1340 |
_bfd_elf_write_section_eh_frame_hdr (abfd, sec) |
_bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info) |
|
bfd *abfd; |
|
|
asection *sec; |
|
1341 |
{ |
{ |
1342 |
|
struct elf_link_hash_table *htab; |
1343 |
struct eh_frame_hdr_info *hdr_info; |
struct eh_frame_hdr_info *hdr_info; |
1344 |
unsigned int ptr_size; |
asection *sec; |
1345 |
bfd_byte *contents; |
bfd_byte *contents; |
1346 |
asection *eh_frame_sec; |
asection *eh_frame_sec; |
1347 |
bfd_size_type size; |
bfd_size_type size; |
1348 |
|
bfd_boolean retval; |
1349 |
|
bfd_vma encoded_eh_frame; |
1350 |
|
|
1351 |
ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS] |
htab = elf_hash_table (info); |
1352 |
== ELFCLASS64) ? 8 : 4; |
hdr_info = &htab->eh_info; |
1353 |
|
sec = hdr_info->hdr_sec; |
1354 |
BFD_ASSERT (elf_section_data (sec)->sec_info_type |
if (sec == NULL) |
1355 |
== ELF_INFO_TYPE_EH_FRAME_HDR); |
return TRUE; |
|
hdr_info = (struct eh_frame_hdr_info *) |
|
|
elf_section_data (sec)->sec_info; |
|
|
if (hdr_info->strip) |
|
|
return true; |
|
1356 |
|
|
1357 |
size = EH_FRAME_HDR_SIZE; |
size = EH_FRAME_HDR_SIZE; |
1358 |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
1359 |
size += 4 + hdr_info->fde_count * 8; |
size += 4 + hdr_info->fde_count * 8; |
1360 |
contents = bfd_malloc (size); |
contents = bfd_malloc (size); |
1361 |
if (contents == NULL) |
if (contents == NULL) |
1362 |
return false; |
return FALSE; |
1363 |
|
|
1364 |
eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); |
eh_frame_sec = bfd_get_section_by_name (abfd, ".eh_frame"); |
1365 |
if (eh_frame_sec == NULL) |
if (eh_frame_sec == NULL) |
1366 |
return false; |
{ |
1367 |
|
free (contents); |
1368 |
|
return FALSE; |
1369 |
|
} |
1370 |
|
|
1371 |
memset (contents, 0, EH_FRAME_HDR_SIZE); |
memset (contents, 0, EH_FRAME_HDR_SIZE); |
1372 |
contents[0] = 1; /* Version */ |
contents[0] = 1; /* Version. */ |
1373 |
contents[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .eh_frame offset */ |
contents[1] = get_elf_backend_data (abfd)->elf_backend_encode_eh_address |
1374 |
|
(abfd, info, eh_frame_sec, 0, sec, 4, |
1375 |
|
&encoded_eh_frame); /* .eh_frame offset. */ |
1376 |
|
|
1377 |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) |
1378 |
{ |
{ |
1379 |
contents[2] = DW_EH_PE_udata4; /* FDE count encoding */ |
contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */ |
1380 |
contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* search table enc */ |
contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */ |
1381 |
} |
} |
1382 |
else |
else |
1383 |
{ |
{ |
1384 |
contents[2] = DW_EH_PE_omit; |
contents[2] = DW_EH_PE_omit; |
1385 |
contents[3] = DW_EH_PE_omit; |
contents[3] = DW_EH_PE_omit; |
1386 |
} |
} |
1387 |
bfd_put_32 (abfd, eh_frame_sec->vma - sec->output_section->vma - 4, |
bfd_put_32 (abfd, encoded_eh_frame, contents + 4); |
1388 |
contents + 4); |
|
1389 |
if (contents[2] != DW_EH_PE_omit) |
if (contents[2] != DW_EH_PE_omit) |
1390 |
{ |
{ |
1391 |
unsigned int i; |
unsigned int i; |
1405 |
} |
} |
1406 |
} |
} |
1407 |
|
|
1408 |
return bfd_set_section_contents (abfd, sec->output_section, |
retval = bfd_set_section_contents (abfd, sec->output_section, |
1409 |
contents, (file_ptr) sec->output_offset, |
contents, (file_ptr) sec->output_offset, |
1410 |
sec->_cooked_size); |
sec->size); |
1411 |
|
free (contents); |
1412 |
|
return retval; |
1413 |
|
} |
1414 |
|
|
1415 |
|
/* Return the width of FDE addresses. This is the default implementation. */ |
1416 |
|
|
1417 |
|
unsigned int |
1418 |
|
_bfd_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) |
1419 |
|
{ |
1420 |
|
return elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4; |
1421 |
|
} |
1422 |
|
|
1423 |
|
/* Decide whether we can use a PC-relative encoding within the given |
1424 |
|
EH frame section. This is the default implementation. */ |
1425 |
|
|
1426 |
|
bfd_boolean |
1427 |
|
_bfd_elf_can_make_relative (bfd *input_bfd ATTRIBUTE_UNUSED, |
1428 |
|
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1429 |
|
asection *eh_frame_section ATTRIBUTE_UNUSED) |
1430 |
|
{ |
1431 |
|
return TRUE; |
1432 |
|
} |
1433 |
|
|
1434 |
|
/* Select an encoding for the given address. Preference is given to |
1435 |
|
PC-relative addressing modes. */ |
1436 |
|
|
1437 |
|
bfd_byte |
1438 |
|
_bfd_elf_encode_eh_address (bfd *abfd ATTRIBUTE_UNUSED, |
1439 |
|
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
1440 |
|
asection *osec, bfd_vma offset, |
1441 |
|
asection *loc_sec, bfd_vma loc_offset, |
1442 |
|
bfd_vma *encoded) |
1443 |
|
{ |
1444 |
|
*encoded = osec->vma + offset - |
1445 |
|
(loc_sec->output_section->vma + loc_sec->output_offset + loc_offset); |
1446 |
|
return DW_EH_PE_pcrel | DW_EH_PE_sdata4; |
1447 |
} |
} |