This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: ld corrupting .cfi_label uses
- From: Alan Modra <amodra at gmail dot com>
- To: Jan Beulich <jbeulich at suse dot com>
- Cc: binutils at sourceware dot org
- Date: Wed, 1 Mar 2017 13:12:46 +1030
- Subject: Re: ld corrupting .cfi_label uses
- Authentication-results: sourceware.org; auth=none
- References: <58B04B47020000780013D936@prv-mh.provo.novell.com> <20170226234208.GA12547@bubble.grove.modra.org> <58B3E32902000078000F9844@prv-mh.provo.novell.com>
On Mon, Feb 27, 2017 at 01:28:25AM -0700, Jan Beulich wrote:
> As said, I agree this ought to be the proper final solution, yet while there's
> no real magic needed here, it'll likely be not exactly a non-intrusive change.
> Still in the case at hand (Linux kernel) there aren't any section groups
> involved, and I think the linker ought to leave the contents of .eh_frame
> untouched unless it actually has a need to remove anything from it. Afaict
> it is solely the padding to a multiple of 8 bytes which actually gets in the
> way in my case. But obviously that's hard to verify without suppressing that
> adjustment first, which didn't look safe to do in a straightforward manner as
> (a) there's a later assertion to that effect and (b) there's no explanation why
> the adjustment is being done in the first place, and hence it's not clear
> under what conditions it may need retaining.
Yeah, I've run into the padding issue myself. It is a pain to deal
with. If one input .eh_frame has larger alignment than other
.eh_frame sections for whatever reason, then padding placed before
that section will be seen as a zero terminator.
I suspect that is why ld ensures FDEs are a multiple of eight in size
(it would be better to look at the output section alignment) because
gcc emits .eh_frame aligned to eight bytes on 64-bit targets. You can
pad with NOPs *inside* an FDE or CIE, not outside.
The following implements my suggestion re. output section alignment.
That may well cure your complaint.
bfd/
* elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Align
FDEs and CIEs to output section alignment, not ptr_size.
(_bfd_elf_write_section_eh_frame): Likewise.
ld/
* testsuite/ld-elf/eh3.d: Adjust to suit alignment change.
diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index 1b03b9b..31c9cd4 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -1326,7 +1326,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,12 +1406,13 @@ _bfd_elf_discard_section_eh_frame
sec_info->cies = NULL;
}
+ eh_alignment = 1 << sec->output_section->alignment_power;
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);
+ offset += size_of_output_cie_fde (ent, eh_alignment);
}
sec->rawsize = sec->size;
@@ -1731,7 +1732,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd,
struct eh_frame_sec_info *sec_info;
struct elf_link_hash_table *htab;
struct eh_frame_hdr_info *hdr_info;
- unsigned int ptr_size;
+ unsigned int ptr_size, eh_alignment;
struct eh_cie_fde *ent;
bfd_size_type sec_size;
@@ -1771,6 +1772,7 @@ _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);
+ eh_alignment = 1 << sec->output_section->alignment_power;
for (ent = sec_info->entry; ent < sec_info->entry + sec_info->count; ++ent)
{
unsigned char *buf, *end;
@@ -1788,7 +1790,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd,
buf = contents + ent->new_offset;
end = buf + ent->size;
- new_size = size_of_output_cie_fde (ent, ptr_size);
+ new_size = size_of_output_cie_fde (ent, eh_alignment);
/* Update the size. It may be shrinked. */
bfd_put_32 (abfd, new_size - 4, buf);
@@ -2062,13 +2064,13 @@ _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
+ have padded CIE/FDE records to multiple of eh_alignment 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)
+ if ((sec_size % eh_alignment) != 0)
abort ();
/* FIXME: octets_per_byte. */
diff --git a/ld/testsuite/ld-elf/eh3.d b/ld/testsuite/ld-elf/eh3.d
index 6ac584a..2228c72 100644
--- a/ld/testsuite/ld-elf/eh3.d
+++ b/ld/testsuite/ld-elf/eh3.d
@@ -7,7 +7,7 @@
Contents of the .eh_frame section:
-0+0000 0+0014 0+0000 CIE
+0+0000 0+001c 0+0000 CIE
Version: 1
Augmentation: ""
Code alignment factor: 1
@@ -22,13 +22,21 @@ Contents of the .eh_frame section:
DW_CFA_nop
DW_CFA_nop
DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
+ DW_CFA_nop
-0+0018 0+001c 0+001c FDE cie=0+0000 pc=0+400078\.\.0+400090
+0+0020 0+001c 0+0024 FDE cie=0+0000 pc=0+400078\.\.0+400090
DW_CFA_advance_loc: 8 to 0+400080
DW_CFA_def_cfa_offset: 16
DW_CFA_offset: r6 \(rbp\) at cfa-16
DW_CFA_advance_loc: 8 to 0+400088
DW_CFA_def_cfa_register: r6 \(rbp\)
-0+0038 ZERO terminator
+0+0040 ZERO terminator
#pass
--
Alan Modra
Australia Development Lab, IBM