int lua_elf_section_t_disassemble (lua_State * L) { struct _elf_section * section; uint_t * address; uint_t address_tmp; unsigned char * data; int disassemble_address = 0; section = lua_check_elf_section(L, 1); if (lua_isuserdata(L, 2)) { address = lua_check_uint_t(L, 2); disassemble_address = 1; lua_pop(L, 2); } else lua_pop(L, 1); if (disassemble_address) { uint_t_set(&address_tmp, address); uint_t_sub(&address_tmp, elf_section_addr(section)); data = elf_section_data(section); lua_dis_instruction(L, &(data[uint_t_get(&address_tmp)]), ELF_CLASS(section->elf)); } else lua_dis_table(L, elf_section_addr(section), elf_section_data(section), int_t_get(elf_section_size(section)), ELF_CLASS(section->elf)); return 1; }
enum sh64_elf_cr_type sh64_get_contents_type (asection *sec, bfd_vma addr, sh64_elf_crange *rangep) { asection *cranges; /* Fill in the range with the boundaries of the section as a default. */ if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour && elf_elfheader (sec->owner)->e_type == ET_EXEC) { rangep->cr_addr = bfd_get_section_vma (sec->owner, sec); rangep->cr_size = sec->size; rangep->cr_type = CRT_NONE; } else return FALSE; /* If none of the pertinent bits are set, then it's a SHcompact (or at least not SHmedia). */ if ((elf_section_data (sec)->this_hdr.sh_flags & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0) { enum sh64_elf_cr_type cr_type = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0 ? CRT_SH5_ISA16 : CRT_DATA); rangep->cr_type = cr_type; return cr_type; } /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia. */ if ((elf_section_data (sec)->this_hdr.sh_flags & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32) { rangep->cr_type = CRT_SH5_ISA32; return CRT_SH5_ISA32; } /* Otherwise, we have to look up the .cranges section. */ cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME); if (cranges == NULL) /* A mixed section but there's no .cranges section. This is probably bad input; it does not comply to specs. */ return CRT_NONE; /* If this call fails, we will still have CRT_NONE in rangep->cr_type and that will be suitable to return. */ sh64_address_in_cranges (cranges, addr, rangep); return rangep->cr_type; }
int lua_elf_section_t_mem_at_address (lua_State * L) { struct _elf_section * section; uint_t * address; uint_t address_tmp; int member_number; int member_size; int i; uint_t uintt; unsigned char * data; int offset; section = lua_check_elf_section(L, 1); address = lua_check_uint_t(L, 2); member_number = luaL_checkinteger(L, 3); member_size = luaL_checkinteger(L, 4); lua_pop(L, 4); data = elf_section_data(section); uint_t_set(&address_tmp, address); uint_t_sub(&address_tmp, elf_section_addr(section)); offset = uint_t_get(&address_tmp); uint_t_set(&address_tmp, address); lua_newtable(L); for (i = 0; i < member_number; i++) { switch (member_size) { case 8 : lua_pushinteger(L, (lua_Integer) i + 1); uint_t_8_set(&uintt, *((uint8_t *) &(data[offset + i]))); lua_push_uint_t(L, &uintt); lua_settable(L, -3); uint_t_add_int(&address_tmp, 1); break; case 16 : lua_pushinteger(L, (lua_Integer) i + 1); uint_t_16_set(&uintt, *((uint16_t *) &(data[offset + i*2]))); lua_push_uint_t(L, &uintt); lua_settable(L, -3); uint_t_add_int(&address_tmp, 2); break; case 32 : lua_pushinteger(L, (lua_Integer) i + 1); uint_t_32_set(&uintt, *((uint32_t *) &(data[offset + i*4]))); lua_push_uint_t(L, &uintt); lua_settable(L, -3); uint_t_add_int(&address_tmp, 4); break; case 64 : lua_pushinteger(L, (lua_Integer) i + 1); uint_t_64_set(&uintt, *((uint64_t *) &(data[offset + i*8]))); lua_push_uint_t(L, &uintt); lua_settable(L, -3); uint_t_add_int(&address_tmp, 8); break; } } return 1; }
int lua_elf_section_t_rop_table (lua_State * L) { struct _elf_section * section; struct _rop_list * rop_list; struct _rop_list * rop_list_first; int rop_depth; int rop_i; uint_t address; section = lua_check_elf_section(L, 1); rop_depth = luaL_checkinteger(L, 2); lua_pop(L, 2); rop_list_first = rop_ret_rops(elf_section_data(section), int_t_get(elf_section_size(section)), rop_depth, ELF_CLASS(section->elf)); rop_list = rop_list_first; rop_i = 1; lua_newtable(L); while (rop_list != NULL) { rop_list_ins(rop_list); uint_t_set(&address, elf_section_addr(section)); uint_t_add_int(&address, rop_list->offset); lua_dis_table(L, &address, rop_list->bytes, rop_list->bytes_size, ELF_CLASS(section->elf)); lua_pushinteger(L, (lua_Integer) rop_i); lua_insert(L, -2); lua_settable(L, -3); rop_i++; rop_list = rop_list->next; } rop_list_destroy(rop_list_first); return 1; }
static bfd_boolean sh64_address_in_cranges (asection *cranges, bfd_vma addr, sh64_elf_crange *rangep) { bfd_byte *cranges_contents; bfd_byte *found_rangep; bfd_size_type cranges_size = cranges->size; /* If the size is not a multiple of the cranges entry size, then something is badly wrong. */ if ((cranges_size % SH64_CRANGE_SIZE) != 0) return FALSE; /* If this section has relocations, then we can't do anything sane. */ if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC) return FALSE; /* Has some kind soul (or previous call) left processed, sorted contents for us? */ if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY) && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED) cranges_contents = cranges->contents; else { if (!bfd_malloc_and_get_section (cranges->owner, cranges, &cranges_contents)) goto error_return; /* Is it sorted? */ if (elf_section_data (cranges)->this_hdr.sh_type != SHT_SH5_CR_SORTED) /* Nope. Lets sort it. */ qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE, SH64_CRANGE_SIZE, bfd_big_endian (cranges->owner) ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl); /* Let's keep it around. */ cranges->contents = cranges_contents; bfd_set_section_flags (cranges->owner, cranges, bfd_get_section_flags (cranges->owner, cranges) | SEC_IN_MEMORY); /* It's sorted now. */ elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED; } /* Try and find a matching range. */ found_rangep = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE, SH64_CRANGE_SIZE, bfd_big_endian (cranges->owner) ? _bfd_sh64_crange_bsearch_cmpb : _bfd_sh64_crange_bsearch_cmpl); /* Fill in a few return values if we found a matching range. */ if (found_rangep) { enum sh64_elf_cr_type cr_type = bfd_get_16 (cranges->owner, SH64_CRANGE_CR_TYPE_OFFSET + found_rangep); bfd_vma cr_addr = bfd_get_32 (cranges->owner, SH64_CRANGE_CR_ADDR_OFFSET + (char *) found_rangep); bfd_size_type cr_size = bfd_get_32 (cranges->owner, SH64_CRANGE_CR_SIZE_OFFSET + (char *) found_rangep); rangep->cr_addr = cr_addr; rangep->cr_size = cr_size; rangep->cr_type = cr_type; return TRUE; } /* There is a .cranges section, but it does not have a descriptor matching this address. */ return FALSE; error_return: if (cranges_contents != NULL) free (cranges_contents); return FALSE; }
bfd * _bfd_elf_link_setup_gnu_properties (struct bfd_link_info *info) { bfd *abfd, *first_pbfd = NULL; elf_property_list *list; asection *sec; bfd_boolean has_properties = FALSE; const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); unsigned int elfclass = bed->s->elfclass; int elf_machine_code = bed->elf_machine_code; /* Find the first relocatable ELF input with GNU properties. */ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) if (bfd_get_flavour (abfd) == bfd_target_elf_flavour && (abfd->flags & DYNAMIC) == 0 && elf_properties (abfd) != NULL) { has_properties = TRUE; /* Ignore GNU properties from ELF objects with different machine code or class. Also skip objects without a GNU_PROPERTY note section. */ if ((elf_machine_code == get_elf_backend_data (abfd)->elf_machine_code) && (elfclass == get_elf_backend_data (abfd)->s->elfclass) && bfd_get_section_by_name (abfd, NOTE_GNU_PROPERTY_SECTION_NAME) != NULL ) { /* Keep .note.gnu.property section in FIRST_PBFD. */ first_pbfd = abfd; break; } } /* Do nothing if there is no .note.gnu.property section. */ if (!has_properties) return NULL; /* Merge .note.gnu.property sections. */ for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link.next) if (abfd != first_pbfd && (abfd->flags & DYNAMIC) == 0) { elf_property_list *null_ptr = NULL; elf_property_list **listp = &null_ptr; /* Merge .note.gnu.property section in relocatable ELF input. */ if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) { list = elf_properties (abfd); /* Ignore GNU properties from ELF objects with different machine code. */ if (list != NULL && (elf_machine_code == get_elf_backend_data (abfd)->elf_machine_code)) listp = &elf_properties (abfd); } else list = NULL; /* Merge properties with FIRST_PBFD. FIRST_PBFD can be NULL when all properties are from ELF objects with different machine code or class. */ if (first_pbfd != NULL) elf_merge_gnu_property_list (info, first_pbfd, listp); if (list != NULL) { /* Discard the .note.gnu.property section in this bfd. */ sec = bfd_get_section_by_name (abfd, NOTE_GNU_PROPERTY_SECTION_NAME); if (sec != NULL) sec->output_section = bfd_abs_section_ptr; } } /* Rewrite .note.gnu.property section so that GNU properties are always sorted by type even if input GNU properties aren't sorted. */ if (first_pbfd != NULL) { bfd_size_type size; bfd_byte *contents; unsigned int align_size = elfclass == ELFCLASS64 ? 8 : 4; sec = bfd_get_section_by_name (first_pbfd, NOTE_GNU_PROPERTY_SECTION_NAME); BFD_ASSERT (sec != NULL); /* Update stack size in .note.gnu.property with -z stack-size=N if N > 0. */ if (info->stacksize > 0) { elf_property *p; bfd_vma stacksize = info->stacksize; p = _bfd_elf_get_property (first_pbfd, GNU_PROPERTY_STACK_SIZE, align_size); if (p->pr_kind == property_unknown) { /* Create GNU_PROPERTY_STACK_SIZE. */ p->u.number = stacksize; p->pr_kind = property_number; } else if (stacksize > p->u.number) p->u.number = stacksize; } else if (elf_properties (first_pbfd) == NULL) { /* Discard .note.gnu.property section if all properties have been removed. */ sec->output_section = bfd_abs_section_ptr; return NULL; } /* Fix up GNU properties. */ if (bed->fixup_gnu_properties) bed->fixup_gnu_properties (info, &elf_properties (first_pbfd)); if (elf_properties (first_pbfd) == NULL) { /* Discard .note.gnu.property section if all properties have been removed. */ sec->output_section = bfd_abs_section_ptr; return NULL; } /* Compute the section size. */ list = elf_properties (first_pbfd); size = elf_get_gnu_property_section_size (list, align_size); /* Update .note.gnu.property section now. */ sec->size = size; contents = (bfd_byte *) bfd_zalloc (first_pbfd, size); elf_write_gnu_properties (first_pbfd, contents, list, size, align_size); /* Cache the section contents for elf_link_input_bfd. */ elf_section_data (sec)->this_hdr.contents = contents; /* If GNU_PROPERTY_NO_COPY_ON_PROTECTED is set, protected data symbol is defined in the shared object. */ if (elf_has_no_copy_on_protected (first_pbfd)) info->extern_protected_data = FALSE; } return first_pbfd; }
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) { #define REQUIRE(COND) \ do \ if (!(COND)) \ goto free_no_table; \ while (0) bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_fde; struct eh_cie_fde *ent, *this_inf; unsigned int hdr_length, hdr_id; struct extended_cie { struct cie cie; unsigned int offset; unsigned int usage_count; unsigned int entry; } *ecies = NULL, *ecie; unsigned int ecie_count = 0, ecie_alloced = 0; struct cie *cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int offset; unsigned int ptr_size; unsigned int entry_alloced; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if (bfd_is_abs_section (sec->output_section)) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; if (hdr_info->cies == NULL && !info->relocatable) hdr_info->cies = htab_try_create (1, cie_hash, cie_eq, free); /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); if (sec->size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* 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). */ REQUIRE (sec->size == (unsigned int) sec->size); ptr_size = (get_elf_backend_data (abfd) ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); buf = ehbuf; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); entry_alloced = 100; #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0)) #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { char *aug; bfd_byte *start, *end, *insns, *insns_end; bfd_size_type length; unsigned int set_loc_count; if (sec_info->count == entry_alloced) { sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + ((entry_alloced + 99) * sizeof (struct eh_cie_fde))); REQUIRE (sec_info); memset (&sec_info->entry[entry_alloced], 0, 100 * sizeof (struct eh_cie_fde)); entry_alloced += 100; } this_inf = sec_info->entry + sec_info->count; last_fde = buf; if ((bfd_size_type) (buf - ehbuf) == sec->size) break; /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); /* 64-bit .eh_frame is not supported. */ REQUIRE (hdr_length != 0xffffffff); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); end = buf + hdr_length; this_inf->offset = last_fde - ehbuf; this_inf->size = 4 + hdr_length; if (hdr_length == 0) { /* A zero-length CIE should only be found at the end of the section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); ENSURE_NO_RELOCS (buf); sec_info->count++; break; } REQUIRE (skip_bytes (&buf, end, 4)); hdr_id = bfd_get_32 (abfd, buf - 4); if (hdr_id == 0) { unsigned int initial_insn_length; /* CIE */ this_inf->cie = 1; if (ecie_count == ecie_alloced) { ecies = bfd_realloc (ecies, (ecie_alloced + 20) * sizeof (*ecies)); REQUIRE (ecies); memset (&ecies[ecie_alloced], 0, 20 * sizeof (*ecies)); ecie_alloced += 20; } cie = &ecies[ecie_count].cie; ecies[ecie_count].offset = this_inf->offset; ecies[ecie_count++].entry = sec_info->count; cie->length = hdr_length; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); /* Cannot handle unknown versions. */ REQUIRE (cie->version == 1 || cie->version == 3); REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); strcpy (cie->augmentation, (char *) buf); buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ REQUIRE (skip_bytes (&buf, end, ptr_size)); SKIP_RELOCS (buf); } REQUIRE (read_uleb128 (&buf, end, &cie->code_align)); REQUIRE (read_sleb128 (&buf, end, &cie->data_align)); if (cie->version == 1) { REQUIRE (buf < end); cie->ra_column = *buf++; } else REQUIRE (read_uleb128 (&buf, end, &cie->ra_column)); ENSURE_NO_RELOCS (buf); cie->lsda_encoding = DW_EH_PE_omit; cie->fde_encoding = DW_EH_PE_omit; cie->per_encoding = DW_EH_PE_omit; aug = cie->augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size)); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': REQUIRE (read_byte (&buf, end, &cie->lsda_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size)); break; case 'R': REQUIRE (read_byte (&buf, end, &cie->fde_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size)); break; case 'S': break; case 'P': { int per_width; REQUIRE (read_byte (&buf, end, &cie->per_encoding)); per_width = get_DW_EH_PE_width (cie->per_encoding, ptr_size); REQUIRE (per_width); if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned) { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); } ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->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; } else { Elf_Internal_Sym *sym; asection *sym_sec; bfd_vma val; sym = &cookie->locsyms[r_symndx]; sym_sec = (bfd_section_from_elf_index (abfd, sym->st_shndx)); if (sym_sec != NULL) { if (sym_sec->kept_section != NULL) sym_sec = sym_sec->kept_section; if (sym_sec->output_section != NULL) { val = (sym->st_value + sym_sec->output_offset + sym_sec->output_section->vma); cie->personality.val = val; cie->local_personality = 1; } } } /* Cope with MIPS-style composite relocations. */ do cookie->rel++; while (GET_RELOC (buf) != NULL); } REQUIRE (skip_bytes (&buf, end, per_width)); REQUIRE (cie->local_personality || cie->personality.h); } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr) cie->make_relative = 1; /* If the CIE doesn't already have an 'R' entry, it's fairly easy to add one, provided that there's no aligned data after the augmentation string. */ else if (cie->fde_encoding == DW_EH_PE_omit && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned) { if (*cie->augmentation == 0) this_inf->add_augmentation_size = 1; this_inf->add_fde_encoding = 1; cie->make_relative = 1; } } if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie->make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie->fde_encoding == DW_EH_PE_omit) cie->fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; if (initial_insn_length <= sizeof (cie->initial_instructions)) { cie->initial_insn_length = initial_insn_length; memcpy (cie->initial_instructions, buf, initial_insn_length); } insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); } else { /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) if (cie_offset == ecie->offset) break; /* Ensure this FDE references one of the CIEs in this input section. */ REQUIRE (ecie != ecies + ecie_count); cie = &ecie->cie; ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) /* This is a FDE against a discarded section. It should be deleted. */ this_inf->removed = 1; else { if (info->shared && (((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr && cie->make_relative == 0) || (cie->fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; (*info->callbacks->einfo) (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" " table being created.\n"), abfd, sec); } ecie->usage_count++; hdr_info->fde_count++; this_inf->cie_inf = (void *) (ecie - ecies); } /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); /* Skip the augmentation size, if present. */ if (cie->augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); else length = 0; /* Of the supported augmentation characters above, only 'L' adds augmentation data to the FDE. This code would need to be adjusted if any future augmentations do the same thing. */ if (cie->lsda_encoding != DW_EH_PE_omit) { this_inf->lsda_offset = buf - start; /* If there's no 'z' augmentation, we don't know where the CFA insns begin. Assume no padding. */ if (cie->augmentation[0] != 'z') length = end - buf; } /* Skip over the augmentation data. */ REQUIRE (skip_bytes (&buf, end, length)); insns = buf; buf = last_fde + 4 + hdr_length; SKIP_RELOCS (buf); } /* Try to interpret the CFA instructions and find the first padding nop. Shrink this_inf's size so that it doesn't include the padding. */ length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); set_loc_count = 0; insns_end = skip_non_nops (insns, end, length, &set_loc_count); /* If we don't understand the CFA instructions, we can't know what needs to be adjusted there. */ if (insns_end == NULL /* For the time being we don't support DW_CFA_set_loc in CIE instructions. */ || (set_loc_count && this_inf->cie)) goto free_no_table; this_inf->size -= end - insns_end; if (insns_end != end && this_inf->cie) { cie->initial_insn_length -= end - insns_end; cie->length -= end - insns_end; } if (set_loc_count && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel || cie->make_relative)) { unsigned int cnt; bfd_byte *p; this_inf->set_loc = bfd_malloc ((set_loc_count + 1) * sizeof (unsigned int)); REQUIRE (this_inf->set_loc); this_inf->set_loc[0] = set_loc_count; p = insns; cnt = 0; while (p < end) { if (*p == DW_CFA_set_loc) this_inf->set_loc[++cnt] = p + 1 - start; REQUIRE (skip_cfa_op (&p, end, length)); } } this_inf->fde_encoding = cie->fde_encoding; this_inf->lsda_encoding = cie->lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Look at all CIEs in this section and determine which can be removed as unused, which can be merged with previous duplicate CIEs and which need to be kept. */ for (ecie = ecies; ecie < ecies + ecie_count; ++ecie) { if (ecie->usage_count == 0) { sec_info->entry[ecie->entry].removed = 1; continue; } ecie->cie.output_sec = sec->output_section; ecie->cie.cie_inf = sec_info->entry + ecie->entry; cie_compute_hash (&ecie->cie); if (hdr_info->cies != NULL) { void **loc = htab_find_slot_with_hash (hdr_info->cies, &ecie->cie, ecie->cie.hash, INSERT); if (loc != NULL) { if (*loc != HTAB_EMPTY_ENTRY) { sec_info->entry[ecie->entry].removed = 1; ecie->cie.cie_inf = ((struct cie *) *loc)->cie_inf; continue; } *loc = malloc (sizeof (struct cie)); if (*loc == NULL) *loc = HTAB_DELETED_ENTRY; else memcpy (*loc, &ecie->cie, sizeof (struct cie)); } } ecie->cie.cie_inf->make_relative = ecie->cie.make_relative; ecie->cie.cie_inf->make_lsda_relative = ecie->cie.make_lsda_relative; ecie->cie.cie_inf->per_encoding_relative = (ecie->cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } /* Ok, now we can assign new offsets. */ offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { if (!ent->cie) { ecie = ecies + (bfd_hostptr_t) ent->cie_inf; ent->cie_inf = ecie->cie.cie_inf; } ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } /* Resize the sec as needed. */ sec->rawsize = sec->size; sec->size = offset; free (ehbuf); if (ecies) free (ecies); return offset != sec->rawsize; free_no_table: (*info->callbacks->einfo) (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), abfd, sec); if (ehbuf) free (ehbuf); if (sec_info) free (sec_info); if (ecies) free (ecies); hdr_info->table = FALSE; return FALSE; #undef REQUIRE }
int lua_elf_symbol_t_disassemble (lua_State * L) { struct lua_elf_symbol_t * symbol_t; struct _elf * elf; struct _elf_symbol symbol; struct _elf_section section; unsigned char * data; int section_i; int symbol_i; uint_t offset; int end_address_set = 0; uint_t end_address; uint_t_8_set(&end_address, 0); symbol_t = lua_check_elf_symbol_t(L, 1); lua_pop(L, 1); elf = symbol_t->section_t->elf_t->elf; // find function sym at next highest address, save it's start address in // end_address for (section_i = 0; section_i < int_t_get(elf_shnum(elf)); section_i++) { elf_section(elf, §ion, section_i); if (int_t_get(elf_section_type(§ion)) == SHT_SYMTAB) { for (symbol_i = 0; symbol_i < elf_section_num(§ion); symbol_i++) { elf_section_symbol(§ion, &symbol, symbol_i); if ( (elf_symbol_type(&symbol) == STT_FUNC) && (uint_t_cmp(elf_symbol_value(&(symbol_t->symbol)), elf_symbol_value(&symbol)) < 0) && (uint_t_cmp(elf_symbol_shndx(&symbol), elf_symbol_shndx(&(symbol_t->symbol))) == 0) && ( (uint_t_cmp(elf_symbol_value(&symbol), &end_address) < 0) || (end_address_set == 0) ) ) { uint_t_set(&end_address, elf_symbol_value(&symbol)); end_address_set = 1; } } } } // end address not set? set it to the end of the linked section if (end_address_set == 0) { elf_section(elf, §ion, uint_t_get(elf_symbol_shndx(&(symbol_t->symbol)))); uint_t_int_t(&end_address, elf_section_size(§ion)); uint_t_add(&end_address, elf_section_addr(§ion)); } // load the linked section elf_section(elf, §ion, uint_t_get(elf_symbol_shndx(&(symbol_t->symbol)))); data = elf_section_data(§ion); uint_t_set(&offset, elf_symbol_value(&(symbol_t->symbol))); uint_t_sub(&offset, elf_section_addr(§ion)); // disassemble that function like it was 1980 lua_dis_table(L, elf_symbol_value(&(symbol_t->symbol)), &(data[uint_t_get(&offset)]), uint_t_get(&end_address) - uint_t_get(elf_symbol_value(&(symbol_t->symbol))), ELF_CLASS(elf)); return 1; }
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) { #define REQUIRE(COND) \ do \ if (!(COND)) \ goto free_no_table; \ while (0) bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_cie, *last_fde; struct eh_cie_fde *ent, *last_cie_inf, *this_inf; struct cie_header hdr; struct cie cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int cie_usage_count, offset; unsigned int ptr_size; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if ((sec->output_section != NULL && bfd_is_abs_section (sec->output_section))) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); if (sec->size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* 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). */ REQUIRE (sec->size == (unsigned int) sec->size); ptr_size = (get_elf_backend_data (abfd) ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); buf = ehbuf; last_cie = NULL; last_cie_inf = NULL; memset (&cie, 0, sizeof (cie)); cie_usage_count = 0; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); sec_info->alloced = 100; #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0)) #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { char *aug; bfd_byte *start, *end, *insns; bfd_size_type length; if (sec_info->count == sec_info->alloced) { struct eh_cie_fde *old_entry = sec_info->entry; sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + ((sec_info->alloced + 99) * sizeof (struct eh_cie_fde))); REQUIRE (sec_info); memset (&sec_info->entry[sec_info->alloced], 0, 100 * sizeof (struct eh_cie_fde)); sec_info->alloced += 100; /* Now fix any pointers into the array. */ if (last_cie_inf >= old_entry && last_cie_inf < old_entry + sec_info->count) last_cie_inf = sec_info->entry + (last_cie_inf - old_entry); } this_inf = sec_info->entry + sec_info->count; last_fde = buf; /* If we are at the end of the section, we still need to decide on whether to output or discard last encountered CIE (if any). */ if ((bfd_size_type) (buf - ehbuf) == sec->size) { hdr.length = 0; hdr.id = (unsigned int) -1; end = buf; } else { /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr.length = bfd_get_32 (abfd, buf - 4); /* 64-bit .eh_frame is not supported. */ REQUIRE (hdr.length != 0xffffffff); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr.length <= sec->size); end = buf + hdr.length; this_inf->offset = last_fde - ehbuf; this_inf->size = 4 + hdr.length; if (hdr.length == 0) { /* A zero-length CIE should only be found at the end of the section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); ENSURE_NO_RELOCS (buf); sec_info->count++; /* Now just finish last encountered CIE processing and break the loop. */ hdr.id = (unsigned int) -1; } else { REQUIRE (skip_bytes (&buf, end, 4)); hdr.id = bfd_get_32 (abfd, buf - 4); REQUIRE (hdr.id != (unsigned int) -1); } } if (hdr.id == 0 || hdr.id == (unsigned int) -1) { unsigned int initial_insn_length; /* CIE */ if (last_cie != NULL) { /* Now check if this CIE is identical to the last CIE, in which case we can remove it provided we adjust all FDEs. Also, it can be removed if we have removed all FDEs using it. */ if ((!info->relocatable && hdr_info->last_cie_sec && (sec->output_section == hdr_info->last_cie_sec->output_section) && cie_compare (&cie, &hdr_info->last_cie) == 0) || cie_usage_count == 0) last_cie_inf->removed = 1; else { hdr_info->last_cie = cie; hdr_info->last_cie_sec = sec; last_cie_inf->make_relative = cie.make_relative; last_cie_inf->make_lsda_relative = cie.make_lsda_relative; last_cie_inf->per_encoding_relative = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } } if (hdr.id == (unsigned int) -1) break; last_cie_inf = this_inf; this_inf->cie = 1; cie_usage_count = 0; memset (&cie, 0, sizeof (cie)); cie.hdr = hdr; REQUIRE (read_byte (&buf, end, &cie.version)); /* Cannot handle unknown versions. */ REQUIRE (cie.version == 1 || cie.version == 3); REQUIRE (strlen ((char *) buf) < sizeof (cie.augmentation)); strcpy (cie.augmentation, (char *) buf); buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ REQUIRE (skip_bytes (&buf, end, ptr_size)); SKIP_RELOCS (buf); } REQUIRE (read_uleb128 (&buf, end, &cie.code_align)); REQUIRE (read_sleb128 (&buf, end, &cie.data_align)); if (cie.version == 1) { REQUIRE (buf < end); cie.ra_column = *buf++; } else REQUIRE (read_uleb128 (&buf, end, &cie.ra_column)); ENSURE_NO_RELOCS (buf); cie.lsda_encoding = DW_EH_PE_omit; cie.fde_encoding = DW_EH_PE_omit; cie.per_encoding = DW_EH_PE_omit; aug = cie.augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; REQUIRE (read_uleb128 (&buf, end, &cie.augmentation_size)); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': REQUIRE (read_byte (&buf, end, &cie.lsda_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size)); break; case 'R': REQUIRE (read_byte (&buf, end, &cie.fde_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie.fde_encoding, ptr_size)); break; case 'P': { int per_width; REQUIRE (read_byte (&buf, end, &cie.per_encoding)); per_width = get_DW_EH_PE_width (cie.per_encoding, ptr_size); REQUIRE (per_width); if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); } ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here, against a global symbol. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->rel->r_info); if (r_symndx >= cookie->locsymcount) { 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; } /* Cope with MIPS-style composite relocations. */ do cookie->rel++; while (GET_RELOC (buf) != NULL); } REQUIRE (skip_bytes (&buf, end, per_width)); } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_relative = 1; /* If the CIE doesn't already have an 'R' entry, it's fairly easy to add one, provided that there's no aligned data after the augmentation string. */ else if (cie.fde_encoding == DW_EH_PE_omit && (cie.per_encoding & 0xf0) != DW_EH_PE_aligned) { if (*cie.augmentation == 0) this_inf->add_augmentation_size = 1; this_inf->add_fde_encoding = 1; cie.make_relative = 1; } } if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie.fde_encoding == DW_EH_PE_omit) cie.fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; if (initial_insn_length <= 50) { cie.initial_insn_length = initial_insn_length; memcpy (cie.initial_instructions, buf, initial_insn_length); } insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); last_cie = last_fde; } else { /* Ensure this FDE uses the last CIE encountered. */ REQUIRE (last_cie); REQUIRE (hdr.id == (unsigned int) (buf - 4 - last_cie)); ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) /* This is a FDE against a discarded section. It should be deleted. */ this_inf->removed = 1; else { if (info->shared && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr && cie.make_relative == 0) || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; } cie_usage_count++; hdr_info->fde_count++; } /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); /* Skip the augmentation size, if present. */ if (cie.augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); else length = 0; /* Of the supported augmentation characters above, only 'L' adds augmentation data to the FDE. This code would need to be adjusted if any future augmentations do the same thing. */ if (cie.lsda_encoding != DW_EH_PE_omit) { this_inf->lsda_offset = buf - start; /* If there's no 'z' augmentation, we don't know where the CFA insns begin. Assume no padding. */ if (cie.augmentation[0] != 'z') length = end - buf; } /* Skip over the augmentation data. */ REQUIRE (skip_bytes (&buf, end, length)); insns = buf; buf = last_fde + 4 + hdr.length; SKIP_RELOCS (buf); } /* Try to interpret the CFA instructions and find the first padding nop. Shrink this_inf's size so that it doesn't including the padding. */ length = get_DW_EH_PE_width (cie.fde_encoding, ptr_size); insns = skip_non_nops (insns, end, length); if (insns != 0) this_inf->size -= end - insns; this_inf->fde_encoding = cie.fde_encoding; this_inf->lsda_encoding = cie.lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Ok, now we can assign new offsets. */ offset = 0; last_cie_inf = hdr_info->last_cie_inf; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { if (ent->cie) last_cie_inf = ent; else ent->cie_inf = last_cie_inf; ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } hdr_info->last_cie_inf = last_cie_inf; /* Resize the sec as needed. */ sec->rawsize = sec->size; sec->size = offset; if (sec->size == 0) sec->flags |= SEC_EXCLUDE; free (ehbuf); return offset != sec->rawsize; free_no_table: if (ehbuf) free (ehbuf); if (sec_info) free (sec_info); hdr_info->table = FALSE; hdr_info->last_cie.hdr.length = 0; return FALSE; #undef REQUIRE }
void _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, asection *sec, struct elf_reloc_cookie *cookie) { #define REQUIRE(COND) \ do \ if (!(COND)) \ goto free_no_table; \ while (0) bfd_byte *ehbuf = NULL, *buf, *end; bfd_byte *last_fde; struct eh_cie_fde *this_inf; unsigned int hdr_length, hdr_id; unsigned int cie_count; struct cie *cie, *local_cies = NULL; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int ptr_size; unsigned int num_cies; unsigned int num_entries; elf_gc_mark_hook_fn gc_mark_hook; htab = elf_hash_table (info); hdr_info = &htab->eh_info; if (hdr_info->parsed_eh_frames) return; if (sec->size == 0) { /* This file does not contain .eh_frame information. */ return; } if (bfd_is_abs_section (sec->output_section)) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return; } /* Read the frame unwind information from abfd. */ REQUIRE (bfd_malloc_and_get_section (abfd, sec, &ehbuf)); if (sec->size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return; } /* 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). */ REQUIRE (sec->size == (unsigned int) sec->size); ptr_size = (get_elf_backend_data (abfd) ->elf_backend_eh_frame_address_size (abfd, sec)); REQUIRE (ptr_size != 0); /* Go through the section contents and work out how many FDEs and CIEs there are. */ buf = ehbuf; end = ehbuf + sec->size; num_cies = 0; num_entries = 0; while (buf != end) { num_entries++; /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, end, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); /* 64-bit .eh_frame is not supported. */ REQUIRE (hdr_length != 0xffffffff); if (hdr_length == 0) break; REQUIRE (skip_bytes (&buf, end, 4)); hdr_id = bfd_get_32 (abfd, buf - 4); if (hdr_id == 0) num_cies++; REQUIRE (skip_bytes (&buf, end, hdr_length - 4)); } sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + (num_entries - 1) * sizeof (struct eh_cie_fde)); REQUIRE (sec_info); /* We need to have a "struct cie" for each CIE in this section. */ local_cies = bfd_zmalloc (num_cies * sizeof (*local_cies)); REQUIRE (local_cies); #define ENSURE_NO_RELOCS(buf) \ REQUIRE (!(cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0)) #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) buf = ehbuf; cie_count = 0; gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; while ((bfd_size_type) (buf - ehbuf) != sec->size) { char *aug; bfd_byte *start, *insns, *insns_end; bfd_size_type length; unsigned int set_loc_count; this_inf = sec_info->entry + sec_info->count; last_fde = buf; /* Read the length of the entry. */ REQUIRE (skip_bytes (&buf, ehbuf + sec->size, 4)); hdr_length = bfd_get_32 (abfd, buf - 4); /* The CIE/FDE must be fully contained in this input section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) + hdr_length <= sec->size); end = buf + hdr_length; this_inf->offset = last_fde - ehbuf; this_inf->size = 4 + hdr_length; this_inf->reloc_index = cookie->rel - cookie->rels; if (hdr_length == 0) { /* A zero-length CIE should only be found at the end of the section. */ REQUIRE ((bfd_size_type) (buf - ehbuf) == sec->size); ENSURE_NO_RELOCS (buf); sec_info->count++; break; } REQUIRE (skip_bytes (&buf, end, 4)); hdr_id = bfd_get_32 (abfd, buf - 4); if (hdr_id == 0) { unsigned int initial_insn_length; /* CIE */ this_inf->cie = 1; /* Point CIE to one of the section-local cie structures. */ cie = local_cies + cie_count++; cie->cie_inf = this_inf; cie->length = hdr_length; cie->output_sec = sec->output_section; start = buf; REQUIRE (read_byte (&buf, end, &cie->version)); /* Cannot handle unknown versions. */ REQUIRE (cie->version == 1 || cie->version == 3); REQUIRE (strlen ((char *) buf) < sizeof (cie->augmentation)); strcpy (cie->augmentation, (char *) buf); buf = (bfd_byte *) strchr ((char *) buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ REQUIRE (skip_bytes (&buf, end, ptr_size)); SKIP_RELOCS (buf); } REQUIRE (read_uleb128 (&buf, end, &cie->code_align)); REQUIRE (read_sleb128 (&buf, end, &cie->data_align)); if (cie->version == 1) { REQUIRE (buf < end); cie->ra_column = *buf++; } else REQUIRE (read_uleb128 (&buf, end, &cie->ra_column)); ENSURE_NO_RELOCS (buf); cie->lsda_encoding = DW_EH_PE_omit; cie->fde_encoding = DW_EH_PE_omit; cie->per_encoding = DW_EH_PE_omit; aug = cie->augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; REQUIRE (read_uleb128 (&buf, end, &cie->augmentation_size)); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': REQUIRE (read_byte (&buf, end, &cie->lsda_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->lsda_encoding, ptr_size)); break; case 'R': REQUIRE (read_byte (&buf, end, &cie->fde_encoding)); ENSURE_NO_RELOCS (buf); REQUIRE (get_DW_EH_PE_width (cie->fde_encoding, ptr_size)); break; case 'S': break; case 'P': { int per_width; REQUIRE (read_byte (&buf, end, &cie->per_encoding)); per_width = get_DW_EH_PE_width (cie->per_encoding, ptr_size); REQUIRE (per_width); if ((cie->per_encoding & 0xf0) == DW_EH_PE_aligned) { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); } ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here. */ REQUIRE (GET_RELOC (buf)); cie->personality.reloc_index = cookie->rel - cookie->rels; /* Cope with MIPS-style composite relocations. */ do cookie->rel++; while (GET_RELOC (buf) != NULL); REQUIRE (skip_bytes (&buf, end, per_width)); } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec))) { if ((cie->fde_encoding & 0xf0) == DW_EH_PE_absptr) this_inf->make_relative = 1; /* If the CIE doesn't already have an 'R' entry, it's fairly easy to add one, provided that there's no aligned data after the augmentation string. */ else if (cie->fde_encoding == DW_EH_PE_omit && (cie->per_encoding & 0xf0) != DW_EH_PE_aligned) { if (*cie->augmentation == 0) this_inf->add_augmentation_size = 1; this_inf->u.cie.add_fde_encoding = 1; this_inf->make_relative = 1; } } if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie->lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie->can_make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie->fde_encoding == DW_EH_PE_omit) cie->fde_encoding = DW_EH_PE_absptr; initial_insn_length = end - buf; if (initial_insn_length <= sizeof (cie->initial_instructions)) { cie->initial_insn_length = initial_insn_length; memcpy (cie->initial_instructions, buf, initial_insn_length); } insns = buf; buf += initial_insn_length; ENSURE_NO_RELOCS (buf); if (hdr_info->merge_cies) this_inf->u.cie.u.full_cie = cie; this_inf->u.cie.per_encoding_relative = (cie->per_encoding & 0x70) == DW_EH_PE_pcrel; } else { asection *rsec; /* Find the corresponding CIE. */ unsigned int cie_offset = this_inf->offset + 4 - hdr_id; for (cie = local_cies; cie < local_cies + cie_count; cie++) if (cie_offset == cie->cie_inf->offset) break; /* Ensure this FDE references one of the CIEs in this input section. */ REQUIRE (cie != local_cies + cie_count); this_inf->u.fde.cie_inf = cie->cie_inf; this_inf->make_relative = cie->cie_inf->make_relative; this_inf->add_augmentation_size = cie->cie_inf->add_augmentation_size; ENSURE_NO_RELOCS (buf); REQUIRE (GET_RELOC (buf)); /* Chain together the FDEs for each section. */ rsec = _bfd_elf_gc_mark_rsec (info, sec, gc_mark_hook, cookie); /* RSEC will be NULL if FDE was cleared out as it was belonging to a discarded SHT_GROUP. */ if (rsec) { REQUIRE (rsec->owner == abfd); this_inf->u.fde.next_for_section = elf_fde_list (rsec); elf_fde_list (rsec) = this_inf; } /* Skip the initial location and address range. */ start = buf; length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); REQUIRE (skip_bytes (&buf, end, 2 * length)); /* Skip the augmentation size, if present. */ if (cie->augmentation[0] == 'z') REQUIRE (read_uleb128 (&buf, end, &length)); else length = 0; /* Of the supported augmentation characters above, only 'L' adds augmentation data to the FDE. This code would need to be adjusted if any future augmentations do the same thing. */ if (cie->lsda_encoding != DW_EH_PE_omit) { SKIP_RELOCS (buf); if (cie->can_make_lsda_relative && GET_RELOC (buf)) cie->cie_inf->u.cie.make_lsda_relative = 1; this_inf->lsda_offset = buf - start; /* If there's no 'z' augmentation, we don't know where the CFA insns begin. Assume no padding. */ if (cie->augmentation[0] != 'z') length = end - buf; } /* Skip over the augmentation data. */ REQUIRE (skip_bytes (&buf, end, length)); insns = buf; buf = last_fde + 4 + hdr_length; /* For NULL RSEC (cleared FDE belonging to a discarded section) the relocations are commonly cleared. We do not sanity check if all these relocations are cleared as (1) relocations to .gcc_except_table will remain uncleared (they will get dropped with the drop of this unused FDE) and (2) BFD already safely drops relocations of any type to .eh_frame by elf_section_ignore_discarded_relocs. TODO: The .gcc_except_table entries should be also filtered as .eh_frame entries; or GCC could rather use COMDAT for them. */ SKIP_RELOCS (buf); } /* Try to interpret the CFA instructions and find the first padding nop. Shrink this_inf's size so that it doesn't include the padding. */ length = get_DW_EH_PE_width (cie->fde_encoding, ptr_size); set_loc_count = 0; insns_end = skip_non_nops (insns, end, length, &set_loc_count); /* If we don't understand the CFA instructions, we can't know what needs to be adjusted there. */ if (insns_end == NULL /* For the time being we don't support DW_CFA_set_loc in CIE instructions. */ || (set_loc_count && this_inf->cie)) goto free_no_table; this_inf->size -= end - insns_end; if (insns_end != end && this_inf->cie) { cie->initial_insn_length -= end - insns_end; cie->length -= end - insns_end; } if (set_loc_count && ((cie->fde_encoding & 0xf0) == DW_EH_PE_pcrel || this_inf->make_relative)) { unsigned int cnt; bfd_byte *p; this_inf->set_loc = bfd_malloc ((set_loc_count + 1) * sizeof (unsigned int)); REQUIRE (this_inf->set_loc); this_inf->set_loc[0] = set_loc_count; p = insns; cnt = 0; while (p < end) { if (*p == DW_CFA_set_loc) this_inf->set_loc[++cnt] = p + 1 - start; REQUIRE (skip_cfa_op (&p, end, length)); } } this_inf->removed = 1; this_inf->fde_encoding = cie->fde_encoding; this_inf->lsda_encoding = cie->lsda_encoding; sec_info->count++; } BFD_ASSERT (sec_info->count == num_entries); BFD_ASSERT (cie_count == num_cies); elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; if (hdr_info->merge_cies) { sec_info->cies = local_cies; local_cies = NULL; } goto success; free_no_table: (*info->callbacks->einfo) (_("%P: error in %B(%A); no .eh_frame_hdr table will be created.\n"), abfd, sec); hdr_info->table = FALSE; if (sec_info) free (sec_info); success: if (ehbuf) free (ehbuf); if (local_cies) free (local_cies); #undef REQUIRE }
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) { struct eh_cie_fde *ent; struct eh_frame_sec_info *sec_info; struct eh_frame_hdr_info *hdr_info; unsigned int ptr_size, offset; sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; if (sec_info == NULL) return FALSE; hdr_info = &elf_hash_table (info)->eh_info; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (ent->size == 4) /* There should only be one zero terminator, on the last input file supplying .eh_frame (crtend.o). Remove any others. */ ent->removed = sec->map_head.s != NULL; else if (!ent->cie) { cookie->rel = cookie->rels + ent->reloc_index; BFD_ASSERT (cookie->rel < cookie->relend && cookie->rel->r_offset == ent->offset + 8); if (!(*reloc_symbol_deleted_p) (ent->offset + 8, cookie)) { if (info->shared && (((ent->fde_encoding & 0xf0) == DW_EH_PE_absptr && ent->make_relative == 0) || (ent->fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; (*info->callbacks->einfo) (_("%P: fde encoding in %B(%A) prevents .eh_frame_hdr" " table being created.\n"), abfd, sec); } ent->removed = 0; hdr_info->fde_count++; ent->u.fde.cie_inf = find_merged_cie (abfd, sec, hdr_info, cookie, ent->u.fde.cie_inf); } } if (sec_info->cies) { free (sec_info->cies); sec_info->cies = NULL; } ptr_size = (get_elf_backend_data (sec->owner) ->elf_backend_eh_frame_address_size (sec->owner, sec)); offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { ent->new_offset = offset; offset += size_of_output_cie_fde (ent, ptr_size); } sec->rawsize = sec->size; sec->size = offset; return offset != sec->rawsize; }
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) { bfd_byte *ehbuf = NULL, *buf; bfd_byte *last_cie, *last_fde; struct cie_header hdr; struct cie cie; struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int leb128_tmp; unsigned int cie_usage_count, last_cie_ndx, i, offset; unsigned int make_relative, make_lsda_relative; bfd_size_type new_size; unsigned int ptr_size; if (sec->_raw_size == 0) { /* This file does not contain .eh_frame information. */ return FALSE; } if ((sec->output_section != NULL && bfd_is_abs_section (sec->output_section))) { /* At least one of the sections is being discarded from the link, so we should just ignore them. */ return FALSE; } htab = elf_hash_table (info); hdr_info = &htab->eh_info; /* Read the frame unwind information from abfd. */ ehbuf = bfd_malloc (sec->_raw_size); if (ehbuf == NULL) goto free_no_table; if (! bfd_get_section_contents (abfd, sec, ehbuf, 0, sec->_raw_size)) goto free_no_table; if (sec->_raw_size >= 4 && bfd_get_32 (abfd, ehbuf) == 0 && cookie->rel == cookie->relend) { /* Empty .eh_frame section. */ free (ehbuf); return FALSE; } /* 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) goto free_no_table; ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4; buf = ehbuf; last_cie = NULL; last_cie_ndx = 0; memset (&cie, 0, sizeof (cie)); cie_usage_count = 0; new_size = sec->_raw_size; make_relative = hdr_info->last_cie.make_relative; make_lsda_relative = hdr_info->last_cie.make_lsda_relative; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); if (sec_info == NULL) goto free_no_table; sec_info->alloced = 100; #define ENSURE_NO_RELOCS(buf) \ if (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf)) \ && cookie->rel->r_info != 0) \ goto free_no_table #define SKIP_RELOCS(buf) \ while (cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ < (bfd_size_type) ((buf) - ehbuf))) \ cookie->rel++ #define GET_RELOC(buf) \ ((cookie->rel < cookie->relend \ && (cookie->rel->r_offset \ == (bfd_size_type) ((buf) - ehbuf))) \ ? cookie->rel : NULL) for (;;) { unsigned char *aug; if (sec_info->count == sec_info->alloced) { sec_info = bfd_realloc (sec_info, sizeof (struct eh_frame_sec_info) + (sec_info->alloced + 99) * sizeof (struct eh_cie_fde)); if (sec_info == NULL) goto free_no_table; memset (&sec_info->entry[sec_info->alloced], 0, 100 * sizeof (struct eh_cie_fde)); sec_info->alloced += 100; } last_fde = buf; /* If we are at the end of the section, we still need to decide on whether to output or discard last encountered CIE (if any). */ if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size) hdr.id = (unsigned int) -1; else { if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) /* No space for CIE/FDE header length. */ goto free_no_table; hdr.length = bfd_get_32 (abfd, buf); if (hdr.length == 0xffffffff) /* 64-bit .eh_frame is not supported. */ goto free_no_table; buf += 4; if ((bfd_size_type) (buf - ehbuf) + hdr.length > sec->_raw_size) /* CIE/FDE not contained fully in this .eh_frame input section. */ goto free_no_table; sec_info->entry[sec_info->count].offset = last_fde - ehbuf; sec_info->entry[sec_info->count].size = 4 + hdr.length; if (hdr.length == 0) { /* CIE with length 0 must be only the last in the section. */ if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) goto free_no_table; ENSURE_NO_RELOCS (buf); sec_info->count++; /* Now just finish last encountered CIE processing and break the loop. */ hdr.id = (unsigned int) -1; } else { hdr.id = bfd_get_32 (abfd, buf); buf += 4; if (hdr.id == (unsigned int) -1) goto free_no_table; } } if (hdr.id == 0 || hdr.id == (unsigned int) -1) { unsigned int initial_insn_length; /* CIE */ if (last_cie != NULL) { /* Now check if this CIE is identical to the last CIE, in which case we can remove it provided we adjust all FDEs. Also, it can be removed if we have removed all FDEs using it. */ if ((!info->relocatable && hdr_info->last_cie_sec && (sec->output_section == hdr_info->last_cie_sec->output_section) && cie_compare (&cie, &hdr_info->last_cie) == 0) || cie_usage_count == 0) { new_size -= cie.hdr.length + 4; sec_info->entry[last_cie_ndx].removed = 1; sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; sec_info->entry[last_cie_ndx].new_offset = hdr_info->last_cie_offset; } else { hdr_info->last_cie = cie; hdr_info->last_cie_sec = sec; hdr_info->last_cie_offset = last_cie - ehbuf; sec_info->entry[last_cie_ndx].make_relative = cie.make_relative; sec_info->entry[last_cie_ndx].make_lsda_relative = cie.make_lsda_relative; sec_info->entry[last_cie_ndx].per_encoding_relative = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; } } if (hdr.id == (unsigned int) -1) break; last_cie_ndx = sec_info->count; sec_info->entry[sec_info->count].cie = 1; cie_usage_count = 0; memset (&cie, 0, sizeof (cie)); cie.hdr = hdr; cie.version = *buf++; /* Cannot handle unknown versions. */ if (cie.version != 1) goto free_no_table; if (strlen (buf) > sizeof (cie.augmentation) - 1) goto free_no_table; strcpy (cie.augmentation, buf); buf = strchr (buf, '\0') + 1; ENSURE_NO_RELOCS (buf); if (buf[0] == 'e' && buf[1] == 'h') { /* GCC < 3.0 .eh_frame CIE */ /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ is private to each CIE, so we don't need it for anything. Just skip it. */ buf += ptr_size; SKIP_RELOCS (buf); } read_uleb128 (cie.code_align, buf); read_sleb128 (cie.data_align, buf); /* Note - in DWARF2 the return address column is an unsigned byte. In DWARF3 it is a ULEB128. We are following DWARF3. For most ports this will not matter as the value will be less than 128. For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC which conforms to the DWARF3 standard. */ read_uleb128 (cie.ra_column, buf); ENSURE_NO_RELOCS (buf); cie.lsda_encoding = DW_EH_PE_omit; cie.fde_encoding = DW_EH_PE_omit; cie.per_encoding = DW_EH_PE_omit; aug = cie.augmentation; if (aug[0] != 'e' || aug[1] != 'h') { if (*aug == 'z') { aug++; read_uleb128 (cie.augmentation_size, buf); ENSURE_NO_RELOCS (buf); } while (*aug != '\0') switch (*aug++) { case 'L': cie.lsda_encoding = *buf++; ENSURE_NO_RELOCS (buf); if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) goto free_no_table; break; case 'R': cie.fde_encoding = *buf++; ENSURE_NO_RELOCS (buf); if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) goto free_no_table; break; case 'P': { int per_width; cie.per_encoding = *buf++; per_width = get_DW_EH_PE_width (cie.per_encoding, ptr_size); if (per_width == 0) goto free_no_table; if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) buf = (ehbuf + ((buf - ehbuf + per_width - 1) & ~((bfd_size_type) per_width - 1))); ENSURE_NO_RELOCS (buf); /* Ensure we have a reloc here, against a global symbol. */ if (GET_RELOC (buf) != NULL) { unsigned long r_symndx; #ifdef BFD64 if (ptr_size == 8) r_symndx = ELF64_R_SYM (cookie->rel->r_info); else #endif r_symndx = ELF32_R_SYM (cookie->rel->r_info); if (r_symndx >= cookie->locsymcount) { 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; } cookie->rel++; } buf += per_width; } break; default: /* Unrecognized augmentation. Better bail out. */ goto free_no_table; } } /* For shared libraries, try to get rid of as many RELATIVE relocs as possible. */ if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_relative_eh_frame (abfd, info, sec)) && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_relative = 1; if (info->shared && (get_elf_backend_data (abfd) ->elf_backend_can_make_lsda_relative_eh_frame (abfd, info, sec)) && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_lsda_relative = 1; /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie.fde_encoding == DW_EH_PE_omit) cie.fde_encoding = DW_EH_PE_absptr; initial_insn_length = cie.hdr.length - (buf - last_fde - 4); if (initial_insn_length <= 50) { cie.initial_insn_length = initial_insn_length; memcpy (cie.initial_instructions, buf, initial_insn_length); } buf += initial_insn_length; ENSURE_NO_RELOCS (buf); last_cie = last_fde; } else { /* Ensure this FDE uses the last CIE encountered. */ if (last_cie == NULL || hdr.id != (unsigned int) (buf - 4 - last_cie)) goto free_no_table; ENSURE_NO_RELOCS (buf); if (GET_RELOC (buf) == NULL) /* This should not happen. */ goto free_no_table; if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) { /* This is a FDE against a discarded section. It should be deleted. */ new_size -= hdr.length + 4; sec_info->entry[sec_info->count].removed = 1; } else { if (info->shared && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr && cie.make_relative == 0) || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) { /* If a shared library uses absolute pointers which we cannot turn into PC relative, don't create the binary search table, since it is affected by runtime relocations. */ hdr_info->table = FALSE; } cie_usage_count++; hdr_info->fde_count++; } if (cie.lsda_encoding != DW_EH_PE_omit) { unsigned int dummy; aug = buf; buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); if (cie.augmentation[0] == 'z') read_uleb128 (dummy, buf); /* If some new augmentation data is added before LSDA in FDE augmentation area, this need to be adjusted. */ sec_info->entry[sec_info->count].lsda_offset = (buf - aug); } buf = last_fde + 4 + hdr.length; SKIP_RELOCS (buf); } sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; sec_info->count++; } elf_section_data (sec)->sec_info = sec_info; sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; /* Ok, now we can assign new offsets. */ offset = 0; last_cie_ndx = 0; for (i = 0; i < sec_info->count; i++) { if (! sec_info->entry[i].removed) { sec_info->entry[i].new_offset = offset; offset += sec_info->entry[i].size; if (sec_info->entry[i].cie) { last_cie_ndx = i; make_relative = sec_info->entry[i].make_relative; make_lsda_relative = sec_info->entry[i].make_lsda_relative; } else { sec_info->entry[i].make_relative = make_relative; sec_info->entry[i].make_lsda_relative = make_lsda_relative; sec_info->entry[i].per_encoding_relative = 0; } } else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) { /* Need to adjust new_offset too. */ BFD_ASSERT (sec_info->entry[last_cie_ndx].offset == sec_info->entry[i].new_offset); sec_info->entry[i].new_offset = sec_info->entry[last_cie_ndx].new_offset; } } if (hdr_info->last_cie_sec == sec) { BFD_ASSERT (sec_info->entry[last_cie_ndx].offset == hdr_info->last_cie_offset); hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; } /* FIXME: Currently it is not possible to shrink sections to zero size at this point, so build a fake minimal CIE. */ if (new_size == 0) new_size = 16; /* Shrink the sec as needed. */ sec->_cooked_size = new_size; 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; hdr_info->last_cie.hdr.length = 0; return FALSE; }