This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: ld corrupting .cfi_label uses


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]