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