From 68f691521af7fe788646af93634bc03d68b57dfd Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 15 Dec 2001 08:54:13 +0000 Subject: [PATCH] * 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. --- bfd/ChangeLog | 11 ++++++ bfd/elf-bfd.h | 2 + bfd/elf-eh-frame.c | 95 +++++++++++++++++++++++++++++++--------------- bfd/elflink.h | 3 ++ 4 files changed, 81 insertions(+), 30 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 81e491306e5..e3cc39f05d2 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,14 @@ +2001-12-15 Jakub Jelinek + + * 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. + 2001-12-14 Alan Modra * elflink.h (elf_bfd_discard_info): Fix segfault when dynobj NULL. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index d1b088a59ba..0346c8d19c1 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1296,6 +1296,8 @@ extern boolean _bfd_elf_write_section_eh_frame PARAMS ((bfd *, asection *, asection *, bfd_byte *)); extern boolean _bfd_elf_write_section_eh_frame_hdr PARAMS ((bfd *, asection *)); +extern boolean _bfd_elf_maybe_strip_eh_frame_hdr + PARAMS ((struct bfd_link_info *)); extern boolean _bfd_elf_link_record_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index f215fca036b..14c690be3db 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 diff --git a/bfd/elflink.h b/bfd/elflink.h index a5e348d15be..311774879ae 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -3002,6 +3002,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, if (dynobj == NULL) return true; + if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) + return false; + if (elf_hash_table (info)->dynamic_sections_created) { struct elf_info_failed eif; -- 2.30.2