source: branches/GNU/src/binutils/bfd/elf-eh-frame.c@ 1467

Last change on this file since 1467 was 608, checked in by (none), 22 years ago

This commit was manufactured by cvs2svn to create branch 'GNU'.

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 33.1 KB
Line 
1/* .eh_frame section optimization.
2 Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
3 Written by Jakub Jelinek <[email protected]>.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21#include "bfd.h"
22#include "sysdep.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25#include "elf/dwarf2.h"
26
27#define EH_FRAME_HDR_SIZE 8
28
29static bfd_vma read_unsigned_leb128
30 PARAMS ((bfd *, char *, unsigned int *));
31static bfd_signed_vma read_signed_leb128
32 PARAMS ((bfd *, char *, unsigned int *));
33static int get_DW_EH_PE_width
34 PARAMS ((int, int));
35static bfd_vma read_value
36 PARAMS ((bfd *, bfd_byte *, int, int));
37static void write_value
38 PARAMS ((bfd *, bfd_byte *, bfd_vma, int));
39static int cie_compare
40 PARAMS ((struct cie *, struct cie *));
41static int vma_compare
42 PARAMS ((const PTR, const PTR));
43
44/* Helper function for reading uleb128 encoded data. */
45
46static bfd_vma
47read_unsigned_leb128 (abfd, buf, bytes_read_ptr)
48 bfd *abfd ATTRIBUTE_UNUSED;
49 char *buf;
50 unsigned int *bytes_read_ptr;
51{
52 bfd_vma result;
53 unsigned int num_read;
54 int shift;
55 unsigned char byte;
56
57 result = 0;
58 shift = 0;
59 num_read = 0;
60 do
61 {
62 byte = bfd_get_8 (abfd, (bfd_byte *) buf);
63 buf ++;
64 num_read ++;
65 result |= (((bfd_vma) byte & 0x7f) << shift);
66 shift += 7;
67 }
68 while (byte & 0x80);
69 * bytes_read_ptr = num_read;
70 return result;
71}
72
73/* Helper function for reading sleb128 encoded data. */
74
75static bfd_signed_vma
76read_signed_leb128 (abfd, buf, bytes_read_ptr)
77 bfd *abfd ATTRIBUTE_UNUSED;
78 char *buf;
79 unsigned int * bytes_read_ptr;
80{
81 bfd_vma result;
82 int shift;
83 int num_read;
84 unsigned char byte;
85
86 result = 0;
87 shift = 0;
88 num_read = 0;
89 do
90 {
91 byte = bfd_get_8 (abfd, (bfd_byte *) buf);
92 buf ++;
93 num_read ++;
94 result |= (((bfd_vma) byte & 0x7f) << shift);
95 shift += 7;
96 }
97 while (byte & 0x80);
98 if (byte & 0x40)
99 result |= (((bfd_vma) -1) << (shift - 7)) << 7;
100 * bytes_read_ptr = num_read;
101 return result;
102}
103
104#define read_uleb128(VAR, BUF) \
105do \
106 { \
107 (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp); \
108 (BUF) += leb128_tmp; \
109 } \
110while (0)
111
112#define read_sleb128(VAR, BUF) \
113do \
114 { \
115 (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); \
116 (BUF) += leb128_tmp; \
117 } \
118while (0)
119
120/* Return 0 if either encoding is variable width, or not yet known to bfd. */
121
122static
123int get_DW_EH_PE_width (encoding, ptr_size)
124 int encoding, ptr_size;
125{
126 /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame
127 was added to bfd. */
128 if ((encoding & 0x60) == 0x60)
129 return 0;
130
131 switch (encoding & 7)
132 {
133 case DW_EH_PE_udata2: return 2;
134 case DW_EH_PE_udata4: return 4;
135 case DW_EH_PE_udata8: return 8;
136 case DW_EH_PE_absptr: return ptr_size;
137 default:
138 break;
139 }
140
141 return 0;
142}
143
144#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0)
145
146/* Read a width sized value from memory. */
147
148static bfd_vma
149read_value (abfd, buf, width, is_signed)
150 bfd *abfd;
151 bfd_byte *buf;
152 int width;
153 int is_signed;
154{
155 bfd_vma value;
156
157 switch (width)
158 {
159 case 2:
160 if (is_signed)
161 value = bfd_get_signed_16 (abfd, buf);
162 else
163 value = bfd_get_16 (abfd, buf);
164 break;
165 case 4:
166 if (is_signed)
167 value = bfd_get_signed_32 (abfd, buf);
168 else
169 value = bfd_get_32 (abfd, buf);
170 break;
171 case 8:
172 if (is_signed)
173 value = bfd_get_signed_64 (abfd, buf);
174 else
175 value = bfd_get_64 (abfd, buf);
176 break;
177 default:
178 BFD_FAIL ();
179 return 0;
180 }
181
182 return value;
183}
184
185/* Store a width sized value to memory. */
186
187static void
188write_value (abfd, buf, value, width)
189 bfd *abfd;
190 bfd_byte *buf;
191 bfd_vma value;
192 int width;
193{
194 switch (width)
195 {
196 case 2: bfd_put_16 (abfd, value, buf); break;
197 case 4: bfd_put_32 (abfd, value, buf); break;
198 case 8: bfd_put_64 (abfd, value, buf); break;
199 default: BFD_FAIL ();
200 }
201}
202
203/* Return zero if C1 and C2 CIEs can be merged. */
204
205static
206int cie_compare (c1, c2)
207 struct cie *c1, *c2;
208{
209 if (c1->hdr.length == c2->hdr.length
210 && c1->version == c2->version
211 && strcmp (c1->augmentation, c2->augmentation) == 0
212 && strcmp (c1->augmentation, "eh") != 0
213 && c1->code_align == c2->code_align
214 && c1->data_align == c2->data_align
215 && c1->ra_column == c2->ra_column
216 && c1->augmentation_size == c2->augmentation_size
217 && c1->personality == c2->personality
218 && c1->per_encoding == c2->per_encoding
219 && c1->lsda_encoding == c2->lsda_encoding
220 && c1->fde_encoding == c2->fde_encoding
221 && (c1->initial_insn_length
222 == c2->initial_insn_length)
223 && memcmp (c1->initial_instructions,
224 c2->initial_instructions,
225 c1->initial_insn_length) == 0)
226 return 0;
227
228 return 1;
229}
230
231/* This function is called for each input file before the .eh_frame
232 section is relocated. It discards duplicate CIEs and FDEs for discarded
233 functions. The function returns TRUE iff any entries have been
234 deleted. */
235
236bfd_boolean
237_bfd_elf_discard_section_eh_frame (abfd, info, sec,
238 reloc_symbol_deleted_p, cookie)
239 bfd *abfd;
240 struct bfd_link_info *info;
241 asection *sec;
242 bfd_boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR));
243 struct elf_reloc_cookie *cookie;
244{
245 bfd_byte *ehbuf = NULL, *buf;