This is the mail archive of the binutils-cvs@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]

[binutils-gdb] Binutils: Always skip only 1 byte for CIE version 1's return address register.


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4ffd290906608e72fd98d627a24aa2c2b6ecf4ce

commit 4ffd290906608e72fd98d627a24aa2c2b6ecf4ce
Author: Tamar Christina <tamar.christina@arm.com>
Date:   Fri Mar 1 11:37:51 2019 +0000

    Binutils: Always skip only 1 byte for CIE version 1's return address register.
    
    According to the specification for the CIE entries, when the CIE version is 1 then
    the return address register field is always 1 byte.  Readelf does this correctly in
    read_cie in dwarf.c but ld does this incorrectly and always tries to read a
    skip_leb128.  If the value here has the top bit set then ld will incorrectly read
    at least another byte, causing either an assert failure or an incorrect address to
    be used in eh_frame.
    
    I'm not sure how to generate a generic test for this as I'd need to write assembly,
    and it's a bit hard to trigger. Essentially the relocated value needs to start with
    something that & 0x70 != 0x10 while trying to write a personality.
    
    bfd/ChangeLog:
    
    	* elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Correct CIE parse.

Diff:
---
 bfd/ChangeLog      |  4 ++++
 bfd/elf-eh-frame.c | 12 ++++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 100c453..68004ea 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,7 @@
+2019-02-28  Tamar Christina  <tamar.christina@arm.com>
+
+	* elf-eh-frame.c (_bfd_elf_write_section_eh_frame): Correct CIE parse.
+
 2019-02-28  Nick Clifton  <nickc@redhat.com>
 
 	PR 24273
diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index a13e81e..6919ac3 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -1993,7 +1993,7 @@ _bfd_elf_write_section_eh_frame (bfd *abfd,
 	      || ent->u.cie.per_encoding_relative)
 	    {
 	      char *aug;
-	      unsigned int action, extra_string, extra_data;
+	      unsigned int version, action, extra_string, extra_data;
 	      unsigned int per_width, per_encoding;
 
 	      /* Need to find 'R' or 'L' augmentation's argument and modify
@@ -2004,13 +2004,17 @@ _bfd_elf_write_section_eh_frame (bfd *abfd,
 	      extra_string = extra_augmentation_string_bytes (ent);
 	      extra_data = extra_augmentation_data_bytes (ent);
 
-	      /* Skip length, id and version.  */
-	      buf += 9;
+	      /* Skip length, id.  */
+	      buf += 8;
+	      version = *buf++;
 	      aug = (char *) buf;
 	      buf += strlen (aug) + 1;
 	      skip_leb128 (&buf, end);
 	      skip_leb128 (&buf, end);
-	      skip_leb128 (&buf, end);
+	      if (version == 1)
+		skip_bytes (&buf, end, 1);
+	      else
+		skip_leb128 (&buf, end);
 	      if (*aug == 'z')
 		{
 		  /* The uleb128 will always be a single byte for the kind


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