summaryrefslogtreecommitdiff
path: root/bfd/elf-eh-frame.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2001-12-15 08:54:13 +0000
committerJakub Jelinek <jakub@redhat.com>2001-12-15 08:54:13 +0000
commit2e8607554b086ca9676ce540325691f2913d2e81 (patch)
tree7c73d0f617a25acc98a3f21d0cff635dcbcfa459 /bfd/elf-eh-frame.c
parentb43aed32c0c3bdf2553ca391b91d8cafcc80421c (diff)
downloadbinutils-redhat-2e8607554b086ca9676ce540325691f2913d2e81.tar.gz
* elf-bfd.h (_bfd_elf_maybe_strip_eh_frame_hdr): New prototype.
* elf-eh-frame.c (struct eh_frame_hdr_info): Add strip. (_bfd_elf_discard_section_eh_frame): Don't create .eh_frame_hdr sec_info here. Free ehbuf. (_bfd_elf_discard_section_eh_frame_hdr): Don't size the section if hdr_info->strip. (_bfd_elf_maybe_strip_eh_frame_hdr): New. * elflink.h (size_dynamic_sections): Call it.
Diffstat (limited to 'bfd/elf-eh-frame.c')
-rw-r--r--bfd/elf-eh-frame.c95
1 files changed, 65 insertions, 30 deletions
diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index f215fca036..14c690be3d 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -86,6 +86,7 @@ struct eh_frame_hdr_info
We build it if we successfully read all .eh_frame input sections
and recognize them. */
boolean table;
+ boolean strip;
};
static bfd_vma read_unsigned_leb128
@@ -246,7 +247,7 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
struct cie_header hdr;
struct cie cie;
struct eh_frame_hdr_info *hdr_info;
- struct eh_frame_sec_info *sec_info;
+ struct eh_frame_sec_info *sec_info = NULL;
unsigned int leb128_tmp;
unsigned int cie_usage_count, last_cie_ndx, i, offset, make_relative;
Elf_Internal_Rela *rel;
@@ -267,23 +268,20 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
return false;
}
+ BFD_ASSERT (elf_section_data (ehdrsec)->sec_info_type
+ == ELF_INFO_TYPE_EH_FRAME_HDR);
+ hdr_info = (struct eh_frame_hdr_info *)
+ elf_section_data (ehdrsec)->sec_info;
+
/* Read the frame unwind information from abfd. */
ehbuf = (bfd_byte *) bfd_malloc (sec->_raw_size);
- if (ehbuf == NULL
- || ! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0,
- sec->_raw_size))
- {
- if (elf_section_data (ehdrsec)->sec_info_type
- != ELF_INFO_TYPE_EH_FRAME_HDR)
- {
- elf_section_data (ehdrsec)->sec_info
- = bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
- elf_section_data (ehdrsec)->sec_info_type
- = ELF_INFO_TYPE_EH_FRAME_HDR;
- }
- return false;
- }
+ if (ehbuf == NULL)
+ goto free_no_table;
+
+ if (! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0,
+ sec->_raw_size))
+ goto free_no_table;
if (sec->_raw_size >= 4
&& bfd_get_32 (abfd, ehbuf) == 0
@@ -294,24 +292,10 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
return false;
}
- if (elf_section_data (ehdrsec)->sec_info_type
- != ELF_INFO_TYPE_EH_FRAME_HDR)
- {
- hdr_info = (struct eh_frame_hdr_info *)
- bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
- hdr_info->table = true;
- elf_section_data (ehdrsec)->sec_info = hdr_info;
- elf_section_data (ehdrsec)->sec_info_type
- = ELF_INFO_TYPE_EH_FRAME_HDR;
- }
- else
- hdr_info = (struct eh_frame_hdr_info *)
- elf_section_data (ehdrsec)->sec_info;
-
/* If .eh_frame section size doesn't fit into int, we cannot handle
it (it would need to use 64-bit .eh_frame format anyway). */
if (sec->_raw_size != (unsigned int) sec->_raw_size)
- return false;
+ goto free_no_table;
ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS]
== ELFCLASS64) ? 8 : 4;
@@ -650,9 +634,12 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec,
if (sec->_cooked_size == 0)
sec->flags |= SEC_EXCLUDE;
+ free (ehbuf);
return new_size != sec->_raw_size;
free_no_table:
+ if (ehbuf)
+ free (ehbuf);
if (sec_info)
free (sec_info);
hdr_info->table = false;
@@ -686,6 +673,8 @@ _bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
hdr_info = (struct eh_frame_hdr_info *)
elf_section_data (sec)->sec_info;
+ if (hdr_info->strip)
+ return false;
sec->_cooked_size = EH_FRAME_HDR_SIZE;
if (hdr_info->table)
sec->_cooked_size += 4 + hdr_info->fde_count * 8;
@@ -696,6 +685,52 @@ _bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec)
return true;
}
+/* This function is called from size_dynamic_sections.
+ It needs to decide whether .eh_frame_hdr should be output or not,
+ because later on it is too late for calling _bfd_strip_section_from_output,
+ since dynamic symbol table has been sized. */
+
+boolean
+_bfd_elf_maybe_strip_eh_frame_hdr (info)
+ struct bfd_link_info *info;
+{
+ asection *sec, *o;
+ bfd *abfd;
+ struct eh_frame_hdr_info *hdr_info;
+
+ sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr");
+ if (sec == NULL)
+ return true;
+
+ hdr_info
+ = bfd_zmalloc (sizeof (struct eh_frame_hdr_info));
+ if (hdr_info == NULL)
+ return false;
+
+ elf_section_data (sec)->sec_info = hdr_info;
+ elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR;
+
+ abfd = NULL;
+ if (info->eh_frame_hdr)
+ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next)
+ {
+ /* Count only sections which have at least a single CIE or FDE.
+ There cannot be any CIE or FDE <= 8 bytes. */
+ o = bfd_get_section_by_name (abfd, ".eh_frame");
+ if (o && o->_raw_size > 8)
+ break;
+ }
+
+ if (abfd == NULL)
+ {
+ _bfd_strip_section_from_output (info, sec);
+ hdr_info->strip = true;
+ }
+ else
+ hdr_info->table = true;
+ return true;
+}
+
/* Adjust an address in the .eh_frame section. Given OFFSET within
SEC, this returns the new offset in the adjusted .eh_frame section,
or -1 if the address refers to a CIE/FDE which has been removed