summaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2017-03-05 14:49:54 +1030
committerAlan Modra <amodra@gmail.com>2017-03-05 14:49:54 +1030
commit2e0ce1c84d328bde4dca24b7cfc8b9c033ed271c (patch)
treeea600af380bd0013091dae62a33abc582fb000b5 /bfd
parent0792e0e1199e76dce19a0f9fbdb29c75b8be8a9b (diff)
downloadbinutils-gdb-2e0ce1c84d328bde4dca24b7cfc8b9c033ed271c.tar.gz
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.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog16
-rw-r--r--bfd/elf-bfd.h6
-rw-r--r--bfd/elf-eh-frame.c83
-rw-r--r--bfd/elf64-ppc.c46
4 files changed, 103 insertions, 48 deletions
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 <amodra@gmail.com>
+
+ * 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 <binutils@ineranves.de>
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