xref: /openbsd-src/gnu/usr.bin/binutils/bfd/elf-eh-frame.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
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