From 2e0ce1c84d328bde4dca24b7cfc8b9c033ed271c Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sun, 5 Mar 2017 14:49:54 +1030 Subject: Align eh_frame FDEs according to their encoding bfd/ * elf-bfd.h (struct eh_cie_fde): Add u.cie.per_encoding_aligned8. * elf-eh-frame.c (size_of_output_cie_fde): Don't align here. (next_cie_fde_offset): New function. (_bfd_elf_parse_eh_frame): Set u.cie.per_encoding_aligned8. (_bfd_elf_discard_section_eh_frame): Align zero terminator to four bytes. Align CIEs to four or eight bytes depending on per_encoding_aligned8. Align FDEs according to their encoding. Pad last FDE to output section alignment. (_bfd_elf_write_section_eh_frame): Adjust to suit. Remove assertion. * elf64-ppc.c (glink_eh_frame_cie): Delete padding. (ppc64_elf_size_stubs): Pad glink eh_frame as per elf-eh-frame.c. (ppc64_elf_finish_dynamic_sections): Adjust to suit. ld/ * testsuite/ld-elf/eh3.d: Adjust for eh_frame alignment change. * testsuite/ld-elf/eh6.d: Likewise. * testsuite/ld-alpha/tlsbin.dd: Likewise. * testsuite/ld-alpha/tlsbin.td: Likewise. * testsuite/ld-alpha/tlsbinr.dd: Likewise. * testsuite/ld-alpha/tlspic.dd: Likewise. * testsuite/ld-alpha/tlspic.rd: Likewise. * testsuite/ld-alpha/tlspic.sd: Likewise. * testsuite/ld-alpha/tlspic.td: Likewise. * testsuite/ld-mips-elf/eh-frame1-n64.d: Likewise. * testsuite/ld-mips-elf/eh-frame2-n64.d: Likewise. * testsuite/ld-mips-elf/eh-frame3.d: Likewise. * testsuite/ld-x86-64/pr20830a.d: Likewise. * testsuite/ld-x86-64/pr21038a.d: Likewise. * testsuite/ld-x86-64/pr21038b.d: Likewise. * testsuite/ld-x86-64/pr21038c.d: Likewise. --- bfd/ChangeLog | 16 +++++++++++ bfd/elf-bfd.h | 6 +++- bfd/elf-eh-frame.c | 83 ++++++++++++++++++++++++++++++++++++++---------------- bfd/elf64-ppc.c | 46 +++++++++++++++--------------- 4 files changed, 103 insertions(+), 48 deletions(-) (limited to 'bfd') diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 848ee7fbf24..92682d56b9c 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2017-03-05 Alan Modra + + * elf-bfd.h (struct eh_cie_fde): Add u.cie.per_encoding_aligned8. + * elf-eh-frame.c (size_of_output_cie_fde): Don't align here. + (next_cie_fde_offset): New function. + (_bfd_elf_parse_eh_frame): Set u.cie.per_encoding_aligned8. + (_bfd_elf_discard_section_eh_frame): Align zero terminator to + four bytes. Align CIEs to four or eight bytes depending on + per_encoding_aligned8. Align FDEs according to their encoding. + Pad last FDE to output section alignment. + (_bfd_elf_write_section_eh_frame): Adjust to suit. Remove + assertion. + * elf64-ppc.c (glink_eh_frame_cie): Delete padding. + (ppc64_elf_size_stubs): Pad glink eh_frame as per elf-eh-frame.c. + (ppc64_elf_finish_dynamic_sections): Adjust to suit. + 2017-03-02 Martin Bickel PR ld/21212 diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index f5a8d75e5a0..9e3d6f5fed8 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -342,6 +342,10 @@ struct eh_cie_fde make_per_encoding_relative is. */ unsigned int per_encoding_relative : 1; + /* True if the CIE contains personality data aligned to a + multiple of eight bytes. */ + unsigned int per_encoding_aligned8 : 1; + /* True if we need to add an 'R' (FDE encoding) entry to the CIE's augmentation data. */ unsigned int add_fde_encoding : 1; @@ -350,7 +354,7 @@ struct eh_cie_fde unsigned int merged : 1; /* Unused bits. */ - unsigned int pad1 : 18; + unsigned int pad1 : 17; } cie; } u; unsigned int reloc_index; diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index 1b03b9b36d4..6967f37395f 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -309,11 +309,10 @@ extra_augmentation_data_bytes (struct eh_cie_fde *entry) return size; } -/* Return the size that ENTRY will have in the output. ALIGNMENT is the - required alignment of ENTRY in bytes. */ +/* Return the size that ENTRY will have in the output. */ static unsigned int -size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) +size_of_output_cie_fde (struct eh_cie_fde *entry) { if (entry->removed) return 0; @@ -321,8 +320,22 @@ size_of_output_cie_fde (struct eh_cie_fde *entry, unsigned int alignment) return 4; return (entry->size + extra_augmentation_string_bytes (entry) - + extra_augmentation_data_bytes (entry) - + alignment - 1) & -alignment; + + extra_augmentation_data_bytes (entry)); +} + +/* Return the offset of the FDE or CIE after ENT. */ + +static unsigned int +next_cie_fde_offset (struct eh_cie_fde *ent, + struct eh_cie_fde *last, + asection *sec) +{ + while (++ent < last) + { + if (!ent->removed) + return ent->new_offset; + } + return sec->size; } /* Assume that the bytes between *ITER and END are CFA instructions. @@ -811,6 +824,8 @@ _bfd_elf_parse_eh_frame (bfd *abfd, struct bfd_link_info *info, { length = -(buf - ehbuf) & (per_width - 1); REQUIRE (skip_bytes (&buf, end, length)); + if (per_width == 8) + this_inf->u.cie.per_encoding_aligned8 = 1; } this_inf->u.cie.personality_offset = buf - start; ENSURE_NO_RELOCS (buf); @@ -1326,7 +1341,7 @@ _bfd_elf_discard_section_eh_frame struct eh_cie_fde *ent; struct eh_frame_sec_info *sec_info; struct eh_frame_hdr_info *hdr_info; - unsigned int ptr_size, offset; + unsigned int ptr_size, offset, eh_alignment; if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) return FALSE; @@ -1406,14 +1421,46 @@ _bfd_elf_discard_section_eh_frame sec_info->cies = NULL; } + /* It may be that some .eh_frame input section has greater alignment + than other .eh_frame sections. In that case we run the risk of + padding with zeros before that section, which would be seen as a + zero terminator. Alignment padding must be added *inside* the + last FDE instead. For other FDEs we align according to their + encoding, in order to align FDE address range entries naturally. */ offset = 0; for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) if (!ent->removed) { + eh_alignment = 4; + if (ent->size == 4) + ; + else if (ent->cie) + { + if (ent->u.cie.per_encoding_aligned8) + eh_alignment = 8; + } + else + { + eh_alignment = get_DW_EH_PE_width (ent->fde_encoding, ptr_size); + if (eh_alignment < 4) + eh_alignment = 4; + } + offset = (offset + eh_alignment - 1) & -eh_alignment; ent->new_offset = offset; - offset += size_of_output_cie_fde (ent, ptr_size); + offset += size_of_output_cie_fde (ent); } + /* Pad the last FDE out to the output section alignment if there are + following sections, in order to ensure no padding between this + section and the next. (Relies on the output section alignment + being the maximum of all input sections alignments, which is the + case unless someone is overriding alignment via scripts.) */ + eh_alignment = 4; + if (sec->map_head.s != NULL + && (sec->map_head.s->size != 4 + || sec->map_head.s->map_head.s != NULL)) + eh_alignment = 1 << sec->output_section->alignment_power; + offset = (offset + eh_alignment - 1) & -eh_alignment; sec->rawsize = sec->size; sec->size = offset; return offset != sec->rawsize; @@ -1732,8 +1779,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; unsigned int ptr_size; - struct eh_cie_fde *ent; - bfd_size_type sec_size; + struct eh_cie_fde *ent, *last_ent; if (sec->sec_info_type != SEC_INFO_TYPE_EH_FRAME) /* FIXME: octets_per_byte. */ @@ -1771,7 +1817,8 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, if (!ent->removed && ent->new_offset < ent->offset) memmove (contents + ent->new_offset, contents + ent->offset, ent->size); - for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent) + last_ent = sec_info->entry + sec_info->count; + for (ent = sec_info->entry; ent < last_ent; ++ent) { unsigned char *buf, *end; unsigned int new_size; @@ -1782,13 +1829,13 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, if (ent->size == 4) { /* Any terminating FDE must be at the end of the section. */ - BFD_ASSERT (ent == sec_info->entry + sec_info->count - 1); + BFD_ASSERT (ent == last_ent - 1); continue; } buf = contents + ent->new_offset; end = buf + ent->size; - new_size = size_of_output_cie_fde (ent, ptr_size); + new_size = next_cie_fde_offset (ent, last_ent, sec) - ent->new_offset; /* Update the size. It may be shrinked. */ bfd_put_32 (abfd, new_size - 4, buf); @@ -2059,18 +2106,6 @@ _bfd_elf_write_section_eh_frame (bfd *abfd, } } - /* We don't align the section to its section alignment since the - runtime library only expects all CIE/FDE records aligned at - the pointer size. _bfd_elf_discard_section_eh_frame should - have padded CIE/FDE records to multiple of pointer size with - size_of_output_cie_fde. */ - sec_size = sec->size; - if (sec_info->count != 0 - && sec_info->entry[sec_info->count - 1].size == 4) - sec_size -= 4; - if ((sec_size % ptr_size) != 0) - abort (); - /* FIXME: octets_per_byte. */ return bfd_set_section_contents (abfd, sec->output_section, contents, (file_ptr) sec->output_offset, diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 5ecd1a3ca12..84cb2140872 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -12232,8 +12232,7 @@ static const unsigned char glink_eh_frame_cie[] = 65, /* RA reg. */ 1, /* Augmentation size. */ DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ - DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */ - 0, 0, 0, 0 + DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ }; /* Stripping output sections is normally done before dynamic section @@ -12686,21 +12685,19 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) && !bfd_is_abs_section (htab->glink_eh_frame->output_section) && htab->glink_eh_frame->output_section->size != 0) { - size_t size = 0, align; + size_t size = 0, align = 4; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - size += 24; + size += (17 + align - 1) & -align; if (htab->glink != NULL && htab->glink->size != 0) - size += 24; + size += (24 + align - 1) & -align; if (size != 0) - size += sizeof (glink_eh_frame_cie); - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - size = (size + align) & ~align; + size += (sizeof (glink_eh_frame_cie) + align - 1) & -align; + align = 1ul << htab->glink_eh_frame->output_section->alignment_power; + size = (size + align - 1) & -align; htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; htab->glink_eh_frame->size = size; } @@ -12745,12 +12742,13 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) return FALSE; htab->glink_eh_frame->contents = p; last_fde = p; + align = 4; memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); /* CIE length (rewrite in case little-endian). */ - last_fde_len = sizeof (glink_eh_frame_cie) - 4; + last_fde_len = ((sizeof (glink_eh_frame_cie) + align - 1) & -align) - 4; bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += sizeof (glink_eh_frame_cie); + p += last_fde_len + 4; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; @@ -12758,9 +12756,9 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) { last_fde = p; - last_fde_len = 20; + last_fde_len = ((17 + align - 1) & -align) - 4; /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); p += 4; /* CIE pointer. */ val = p - htab->glink_eh_frame->contents; @@ -12774,14 +12772,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) /* Augmentation. */ p += 1; /* Pad. */ - p += 7; + p += ((17 + align - 1) & -align) - 17; } if (htab->glink != NULL && htab->glink->size != 0) { last_fde = p; - last_fde_len = 20; + last_fde_len = ((24 + align - 1) & -align) - 4; /* FDE length. */ - bfd_put_32 (htab->elf.dynobj, 20, p); + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); p += 4; /* CIE pointer. */ val = p - htab->glink_eh_frame->contents; @@ -12802,15 +12800,14 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) *p++ = DW_CFA_advance_loc + 4; *p++ = DW_CFA_restore_extended; *p++ = 65; + p += ((24 + align - 1) & -align) - 24; } /* Subsume any padding into the last FDE if user .eh_frame sections are aligned more than glink_eh_frame. Otherwise any zero padding will be seen as a terminator. */ + align = 1ul << htab->glink_eh_frame->output_section->alignment_power; size = p - htab->glink_eh_frame->contents; - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - pad = ((size + align) & ~align) - size; + pad = ((size + align - 1) & -align) - size; htab->glink_eh_frame->size = size + pad; bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); } @@ -15667,8 +15664,10 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, bfd_vma val; bfd_byte *p; asection *stub_sec; + size_t align = 4; - p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie); + p = htab->glink_eh_frame->contents; + p += (sizeof (glink_eh_frame_cie) + align - 1) & -align; for (stub_sec = htab->params->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) @@ -15698,7 +15697,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, /* Augmentation. */ p += 1; /* Pad. */ - p += 7; + p += ((17 + align - 1) & -align) - 17; } if (htab->glink != NULL && htab->glink->size != 0) { @@ -15728,6 +15727,7 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, p += 1; /* Ops. */ p += 7; + p += ((24 + align - 1) & -align) - 24; } if (htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME -- cgit v1.2.1