[lld] r337610 - [ELF] Check eh_frame_hdr overflow with PC offsets instead of PC absolute addresses

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 20 13:27:42 PDT 2018


Author: maskray
Date: Fri Jul 20 13:27:42 2018
New Revision: 337610

URL: http://llvm.org/viewvc/llvm-project?rev=337610&view=rev
Log:
[ELF] Check eh_frame_hdr overflow with PC offsets instead of PC absolute addresses

Reviewers: grimar, ruiu, espindola

Subscribers: emaste, arichardson, llvm-commits

Differential Revision: https://reviews.llvm.org/D49607

Added:
    lld/trunk/test/ELF/Inputs/eh-frame-pcrel-overflow.s
    lld/trunk/test/ELF/eh-frame-pcrel-overflow.s
Removed:
    lld/trunk/test/ELF/eh-frame-pcaddr-overflow.s
Modified:
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=337610&r1=337609&r2=337610&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Fri Jul 20 13:27:42 2018
@@ -502,16 +502,31 @@ std::vector<EhFrameSection::FdeData> EhF
   uint8_t *Buf = getParent()->Loc + OutSecOff;
   std::vector<FdeData> Ret;
 
+  uint64_t VA = InX::EhFrameHdr->getVA();
   for (CieRecord *Rec : CieRecords) {
     uint8_t Enc = getFdeEncoding(Rec->Cie);
     for (EhSectionPiece *Fde : Rec->Fdes) {
       uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc);
-      if (Pc > UINT32_MAX)
-        fatal(toString(Fde->Sec) + ": PC address is too large: " + Twine(Pc));
-      uint32_t FdeVA = getParent()->Addr + Fde->OutputOff;
-      Ret.push_back({(uint32_t)Pc, FdeVA});
+      uint64_t FdeVA = getParent()->Addr + Fde->OutputOff;
+      if (!isInt<32>(Pc - VA))
+        fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" +
+              Twine::utohexstr(Pc - VA));
+      Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)});
     }
   }
+
+  // Sort the FDE list by their PC and uniqueify. Usually there is only
+  // one FDE for a PC (i.e. function), but if ICF merges two functions
+  // into one, there can be more than one FDEs pointing to the address.
+  auto Less = [](const FdeData &A, const FdeData &B) {
+    return A.PcRel < B.PcRel;
+  };
+  std::stable_sort(Ret.begin(), Ret.end(), Less);
+  auto Eq = [](const FdeData &A, const FdeData &B) {
+    return A.PcRel == B.PcRel;
+  };
+  Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end());
+
   return Ret;
 }
 
@@ -2532,14 +2547,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf
 
   std::vector<FdeData> Fdes = InX::EhFrame->getFdeData();
 
-  // Sort the FDE list by their PC and uniqueify. Usually there is only
-  // one FDE for a PC (i.e. function), but if ICF merges two functions
-  // into one, there can be more than one FDEs pointing to the address.
-  auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; };
-  std::stable_sort(Fdes.begin(), Fdes.end(), Less);
-  auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; };
-  Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end());
-
   Buf[0] = 1;
   Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
   Buf[2] = DW_EH_PE_udata4;
@@ -2548,10 +2555,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf
   write32(Buf + 8, Fdes.size());
   Buf += 12;
 
-  uint64_t VA = this->getVA();
   for (FdeData &Fde : Fdes) {
-    write32(Buf, Fde.Pc - VA);
-    write32(Buf + 4, Fde.FdeVA - VA);
+    write32(Buf, Fde.PcRel);
+    write32(Buf + 4, Fde.FdeVARel);
     Buf += 8;
   }
 }

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=337610&r1=337609&r2=337610&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Fri Jul 20 13:27:42 2018
@@ -79,8 +79,8 @@ public:
   size_t NumFdes = 0;
 
   struct FdeData {
-    uint32_t Pc;
-    uint32_t FdeVA;
+    uint32_t PcRel;
+    uint32_t FdeVARel;
   };
 
   std::vector<FdeData> getFdeData() const;

Added: lld/trunk/test/ELF/Inputs/eh-frame-pcrel-overflow.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/eh-frame-pcrel-overflow.s?rev=337610&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/eh-frame-pcrel-overflow.s (added)
+++ lld/trunk/test/ELF/Inputs/eh-frame-pcrel-overflow.s Fri Jul 20 13:27:42 2018
@@ -0,0 +1,25 @@
+.text
+.global foo
+foo:
+  ret
+
+.section .eh_frame, "a"
+  .long 12   # Size
+  .long 0x00 # ID
+  .byte 0x01 # Version.
+
+  .byte 0x52 # Augmentation string: 'R','\0'
+  .byte 0x00
+
+  .byte 0x01
+
+  .byte 0x01 # LEB128
+  .byte 0x01 # LEB128
+
+  .byte 0x00 # DW_EH_PE_absptr
+
+  .byte 0xFF
+
+  .long 12  # Size
+  .long 0x14 # ID
+  .quad foo + 0x90000000

Removed: lld/trunk/test/ELF/eh-frame-pcaddr-overflow.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-pcaddr-overflow.s?rev=337609&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-pcaddr-overflow.s (original)
+++ lld/trunk/test/ELF/eh-frame-pcaddr-overflow.s (removed)
@@ -1,32 +0,0 @@
-# REQUIRES: x86
-
-# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-# RUN: not ld.lld --eh-frame-hdr --section-start .text=0x1000000000000000 \
-# RUN:   %t.o -o /dev/null 2>&1 | FileCheck %s
-# CHECK: error: {{.*}}.o:(.eh_frame): PC address is too large: 2387527121043355528
-
-.text
-.global foo
-foo:
- nop
-
-.section .eh_frame, "a"
-  .long 12   # Size
-  .long 0x00 # ID
-  .byte 0x01 # Version.
-  
-  .byte 0x52 # Augmentation string: 'R','\0'
-  .byte 0x00
-  
-  .byte 0x01
-  
-  .byte 0x01 # LEB128
-  .byte 0x01 # LEB128
-
-  .byte 0x00 # DW_EH_PE_absptr
-
-  .byte 0xFF
- 
-  .long 12  # Size
-  .long 0x14 # ID
-  .quad foo + 0x1122334455667788

Added: lld/trunk/test/ELF/eh-frame-pcrel-overflow.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-pcrel-overflow.s?rev=337610&view=auto
==============================================================================
--- lld/trunk/test/ELF/eh-frame-pcrel-overflow.s (added)
+++ lld/trunk/test/ELF/eh-frame-pcrel-overflow.s Fri Jul 20 13:27:42 2018
@@ -0,0 +1,33 @@
+# REQUIRES: x86
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/eh-frame-pcrel-overflow.s -o %t1.o
+# RUN: ld.lld --eh-frame-hdr -Ttext=0x90000000 %t.o -o /dev/null
+# RUN: not ld.lld --eh-frame-hdr %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s
+# CHECK: error: {{.*}}.o:(.eh_frame): PC offset is too large: 0x90000eac
+
+.text
+.global _start
+_start:
+  ret
+
+.section .eh_frame, "a"
+  .long 12   # Size
+  .long 0x00 # ID
+  .byte 0x01 # Version.
+
+  .byte 0x52 # Augmentation string: 'R','\0'
+  .byte 0x00
+
+  .byte 0x01
+
+  .byte 0x01 # LEB128
+  .byte 0x01 # LEB128
+
+  .byte 0x00 # DW_EH_PE_absptr
+
+  .byte 0xFF
+
+  .long 12  # Size
+  .long 0x14 # ID
+  .quad _start + 0x70000000




More information about the llvm-commits mailing list