+static bfd_boolean
+mark_entry (struct bfd_link_info *info, asection *sec,
+ struct eh_cie_fde *ent, elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ /* FIXME: octets_per_byte. */
+ for (cookie->rel = cookie->rels + ent->reloc_index;
+ cookie->rel < cookie->relend
+ && cookie->rel->r_offset < ent->offset + ent->size;
+ cookie->rel++)
+ if (!_bfd_elf_gc_mark_reloc (info, sec, gc_mark_hook, cookie))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Mark all the relocations against FDEs that relate to code in input
+ section SEC. The FDEs belong to .eh_frame section EH_FRAME, whose
+ relocations are described by COOKIE. */
+
+bfd_boolean
+_bfd_elf_gc_mark_fdes (struct bfd_link_info *info, asection *sec,
+ asection *eh_frame, elf_gc_mark_hook_fn gc_mark_hook,
+ struct elf_reloc_cookie *cookie)
+{
+ struct eh_cie_fde *fde, *cie;
+
+ for (fde = elf_fde_list (sec); fde; fde = fde->u.fde.next_for_section)
+ {
+ if (!mark_entry (info, eh_frame, fde, gc_mark_hook, cookie))
+ return FALSE;
+
+ /* At this stage, all cie_inf fields point to local CIEs, so we
+ can use the same cookie to refer to them. */
+ cie = fde->u.fde.cie_inf;
+ if (cie != NULL && !cie->u.cie.gc_mark)
+ {
+ cie->u.cie.gc_mark = 1;
+ if (!mark_entry (info, eh_frame, cie, gc_mark_hook, cookie))
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/* Input section SEC of ABFD is an .eh_frame section that contains the
+ CIE described by CIE_INF. Return a version of CIE_INF that is going
+ to be kept in the output, adding CIE_INF to the output if necessary.
+
+ HDR_INFO is the .eh_frame_hdr information and COOKIE describes the
+ relocations in REL. */
+
+static struct eh_cie_fde *
+find_merged_cie (bfd *abfd, struct bfd_link_info *info, asection *sec,
+ struct eh_frame_hdr_info *hdr_info,
+ struct elf_reloc_cookie *cookie,
+ struct eh_cie_fde *cie_inf)
+{
+ unsigned long r_symndx;
+ struct cie *cie, *new_cie;
+ Elf_Internal_Rela *rel;
+ void **loc;
+
+ /* Use CIE_INF if we have already decided to keep it. */
+ if (!cie_inf->removed)
+ return cie_inf;
+
+ /* If we have merged CIE_INF with another CIE, use that CIE instead. */
+ if (cie_inf->u.cie.merged)
+ return cie_inf->u.cie.u.merged_with;
+
+ cie = cie_inf->u.cie.u.full_cie;
+
+ /* Assume we will need to keep CIE_INF. */
+ cie_inf->removed = 0;
+ cie_inf->u.cie.u.sec = sec;
+
+ /* If we are not merging CIEs, use CIE_INF. */
+ if (cie == NULL)
+ return cie_inf;
+
+ if (cie->per_encoding != DW_EH_PE_omit)
+ {
+ bfd_boolean per_binds_local;
+
+ /* Work out the address of personality routine, or at least
+ enough info that we could calculate the address had we made a
+ final section layout. The symbol on the reloc is enough,
+ either the hash for a global, or (bfd id, index) pair for a
+ local. The assumption here is that no one uses addends on
+ the reloc. */
+ rel = cookie->rels + cie->personality.reloc_index;
+ memset (&cie->personality, 0, sizeof (cie->personality));
+#ifdef BFD64
+ if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ else
+#endif
+ r_symndx = ELF32_R_SYM (rel->r_info);
+ if (r_symndx >= cookie->locsymcount
+ || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL)
+ {
+ struct elf_link_hash_entry *h;
+
+ r_symndx -= cookie->extsymoff;
+ h = cookie->sym_hashes[r_symndx];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ cie->personality.h = h;
+ per_binds_local = SYMBOL_REFERENCES_LOCAL (info, h);
+ }
+ else
+ {
+ Elf_Internal_Sym *sym;
+ asection *sym_sec;
+
+ sym = &cookie->locsyms[r_symndx];
+ sym_sec = bfd_section_from_elf_index (abfd, sym->st_shndx);
+ if (sym_sec == NULL)
+ return cie_inf;
+
+ if (sym_sec->kept_section != NULL)
+ sym_sec = sym_sec->kept_section;
+ if (sym_sec->output_section == NULL)
+ return cie_inf;
+
+ cie->local_personality = 1;
+ cie->personality.sym.bfd_id = abfd->id;
+ cie->personality.sym.index = r_symndx;
+ per_binds_local = TRUE;
+ }
+
+ if (per_binds_local
+ && bfd_link_pic (info)
+ && (cie->per_encoding & 0x70) == DW_EH_PE_absptr
+ && (get_elf_backend_data (abfd)
+ ->elf_backend_can_make_relative_eh_frame (abfd, info, sec)))
+ {
+ cie_inf->u.cie.make_per_encoding_relative = 1;
+ cie_inf->u.cie.per_encoding_relative = 1;
+ }
+ }
+
+ /* See if we can merge this CIE with an earlier one. */
+ cie_compute_hash (cie);
+ if (hdr_info->u.dwarf.cies == NULL)
+ {
+ hdr_info->u.dwarf.cies = htab_try_create (1, cie_hash, cie_eq, free);
+ if (hdr_info->u.dwarf.cies == NULL)
+ return cie_inf;
+ }
+ loc = htab_find_slot_with_hash (hdr_info->u.dwarf.cies, cie,
+ cie->hash, INSERT);
+ if (loc == NULL)
+ return cie_inf;
+
+ new_cie = (struct cie *) *loc;
+ if (new_cie == NULL)
+ {
+ /* Keep CIE_INF and record it in the hash table. */
+ new_cie = (struct cie *) malloc (sizeof (struct cie));
+ if (new_cie == NULL)
+ return cie_inf;
+
+ memcpy (new_cie, cie, sizeof (struct cie));
+ *loc = new_cie;
+ }
+ else
+ {
+ /* Merge CIE_INF with NEW_CIE->CIE_INF. */
+ cie_inf->removed = 1;
+ cie_inf->u.cie.merged = 1;
+ cie_inf->u.cie.u.merged_with = new_cie->cie_inf;
+ if (cie_inf->u.cie.make_lsda_relative)
+ new_cie->cie_inf->u.cie.make_lsda_relative = 1;
+ }
+ return new_cie->cie_inf;
+}
+
+/* This function is called for each input file before the .eh_frame
+ section is relocated. It discards duplicate CIEs and FDEs for discarded
+ functions. The function returns TRUE iff any entries have been
+ deleted. */
+
+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)