Relax address updates in the eh_frame section.
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 28 Dec 2010 05:39:27 +0000 (05:39 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 28 Dec 2010 05:39:27 +0000 (05:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122591 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCAssembler.h
include/llvm/MC/MCDwarf.h
include/llvm/MC/MCObjectStreamer.h
include/llvm/MC/MCStreamer.h
lib/MC/MCAssembler.cpp
lib/MC/MCDwarf.cpp
lib/MC/MCObjectStreamer.cpp
test/MC/ELF/cfi-def-cfa-offset.s

index 65f01e7772a2602e73259df635316e1661147bc9..79d2c8ea41ae4e6f71ed41d0c19d160884eb92ae 100644 (file)
@@ -52,6 +52,7 @@ public:
     FT_Inst,
     FT_Org,
     FT_Dwarf,
+    FT_DwarfFrame,
     FT_LEB
   };
 
@@ -369,7 +370,7 @@ class MCDwarfLineAddrFragment : public MCFragment {
 
 public:
   MCDwarfLineAddrFragment(int64_t _LineDelta, const MCExpr &_AddrDelta,
-                      MCSectionData *SD = 0)
+                      MCSectionData *SD)
     : MCFragment(FT_Dwarf, SD),
       LineDelta(_LineDelta), AddrDelta(&_AddrDelta) { Contents.push_back(0); }
 
@@ -391,6 +392,34 @@ public:
   static bool classof(const MCDwarfLineAddrFragment *) { return true; }
 };
 
+class MCDwarfCallFrameFragment : public MCFragment {
+  /// AddrDelta - The expression for the difference of the two symbols that
+  /// make up the address delta between two .cfi_* dwarf directives.
+  const MCExpr *AddrDelta;
+
+  SmallString<8> Contents;
+
+public:
+  MCDwarfCallFrameFragment(const MCExpr &_AddrDelta,  MCSectionData *SD)
+    : MCFragment(FT_DwarfFrame, SD),
+      AddrDelta(&_AddrDelta) { Contents.push_back(0); }
+
+  /// @name Accessors
+  /// @{
+
+  const MCExpr &getAddrDelta() const { return *AddrDelta; }
+
+  SmallString<8> &getContents() { return Contents; }
+  const SmallString<8> &getContents() const { return Contents; }
+
+  /// @}
+
+  static bool classof(const MCFragment *F) {
+    return F->getKind() == MCFragment::FT_DwarfFrame;
+  }
+  static bool classof(const MCDwarfCallFrameFragment *) { return true; }
+};
+
 // FIXME: Should this be a separate class, or just merged into MCSection? Since
 // we anticipate the fast path being through an MCAssembler, the only reason to
 // keep it out is for API abstraction.
@@ -705,6 +734,8 @@ private:
   bool RelaxLEB(MCAsmLayout &Layout, MCLEBFragment &IF);
 
   bool RelaxDwarfLineAddr(MCAsmLayout &Layout, MCDwarfLineAddrFragment &DF);
+  bool RelaxDwarfCallFrameFragment(MCAsmLayout &Layout,
+                                   MCDwarfCallFrameFragment &DF);
 
   /// FinishLayout - Finalize a layout, including fragment lowering.
   void FinishLayout(MCAsmLayout &Layout);
index 26c28294abed8106a21a4af71f89cda60e19fec2..00b94c9e6ae827adf3f343d3f88cb61de72e99ea 100644 (file)
@@ -25,6 +25,7 @@
 namespace llvm {
   class MachineMove;
   class MCContext;
+  class MCExpr;
   class MCSection;
   class MCSectionData;
   class MCStreamer;
@@ -245,6 +246,8 @@ namespace llvm {
     // This emits the frame info section.
     //
     static void Emit(MCStreamer &streamer);
+    static void EmitAdvanceLoc(MCStreamer &Streamer, uint64_t AddrDelta);
+    static void EncodeAdvanceLoc(uint64_t AddrDelta, raw_ostream &OS);
   };
 } // end namespace llvm
 
index 17ba09e3a0bc9121d4750543da73a8d20f2f0a19..f6fd9d73c7bf141bb63d7398eb83635b6bbcaeb7 100644 (file)
@@ -71,6 +71,8 @@ public:
   virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta,
                                         const MCSymbol *LastLabel,
                                         const MCSymbol *Label);
+  virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
+                                         const MCSymbol *Label);
   virtual void Finish();
 
   /// @}
index ef2238da14f7a2f9f178ca0e79471de8ee0c1cec..345f40109f32c8531f423cfd5710d1900c5d5c45 100644 (file)
@@ -386,6 +386,10 @@ namespace llvm {
                                           const MCSymbol *LastLabel,
                                           const MCSymbol *Label) = 0;
 
+    virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
+                                           const MCSymbol *Label) {
+    }
+
     void EmitDwarfSetLineAddr(int64_t LineDelta, const MCSymbol *Label,
                               int PointerSize);
 
index 030ff9873969d62bf7596340ac274089466d475b..5b291490f71a632da7053bf8ad5d5fd4fc9c7ed9 100644 (file)
@@ -323,6 +323,8 @@ uint64_t MCAssembler::ComputeFragmentSize(const MCAsmLayout &Layout,
 
   case MCFragment::FT_Dwarf:
     return cast<MCDwarfLineAddrFragment>(F).getContents().size();
+  case MCFragment::FT_DwarfFrame:
+    return cast<MCDwarfCallFrameFragment>(F).getContents().size();
   }
 
   assert(0 && "invalid fragment kind");
@@ -453,6 +455,11 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout,
     OW->WriteBytes(OF.getContents().str());
     break;
   }
+  case MCFragment::FT_DwarfFrame: {
+    const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F);
+    OW->WriteBytes(CF.getContents().str());
+    break;
+  }
   }
 
   assert(OW->getStream().tell() - Start == FragmentSize);
@@ -712,6 +719,21 @@ bool MCAssembler::RelaxDwarfLineAddr(MCAsmLayout &Layout,
   return OldSize != Data.size();
 }
 
+bool MCAssembler::RelaxDwarfCallFrameFragment(MCAsmLayout &Layout,
+                                              MCDwarfCallFrameFragment &DF) {
+  int64_t AddrDelta = 0;
+  uint64_t OldSize = DF.getContents().size();
+  bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout);
+  (void)IsAbs;
+  assert(IsAbs);
+  SmallString<8> &Data = DF.getContents();
+  Data.clear();
+  raw_svector_ostream OSE(Data);
+  MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OSE);
+  OSE.flush();
+  return OldSize != Data.size();
+}
+
 bool MCAssembler::LayoutSectionOnce(MCAsmLayout &Layout,
                                     MCSectionData &SD) {
   MCFragment *FirstInvalidFragment = NULL;
@@ -730,9 +752,14 @@ bool MCAssembler::LayoutSectionOnce(MCAsmLayout &Layout,
       relaxedFrag = RelaxDwarfLineAddr(Layout,
                                        *cast<MCDwarfLineAddrFragment>(it2));
       break;
-        case MCFragment::FT_LEB:
-          relaxedFrag = RelaxLEB(Layout, *cast<MCLEBFragment>(it2));
-          break;
+    case MCFragment::FT_DwarfFrame:
+      relaxedFrag =
+        RelaxDwarfCallFrameFragment(Layout,
+                                    *cast<MCDwarfCallFrameFragment>(it2));
+      break;
+    case MCFragment::FT_LEB:
+      relaxedFrag = RelaxLEB(Layout, *cast<MCLEBFragment>(it2));
+      break;
     }
     // Update the layout, and remember that we relaxed.
     if (relaxedFrag && !FirstInvalidFragment)
@@ -789,6 +816,7 @@ void MCFragment::dump() {
   case MCFragment::FT_Inst:  OS << "MCInstFragment"; break;
   case MCFragment::FT_Org:   OS << "MCOrgFragment"; break;
   case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break;
+  case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break;
   case MCFragment::FT_LEB:   OS << "MCLEBFragment"; break;
   }
 
@@ -855,6 +883,12 @@ void MCFragment::dump() {
        << " LineDelta:" << OF->getLineDelta();
     break;
   }
+  case MCFragment::FT_DwarfFrame:  {
+    const MCDwarfCallFrameFragment *CF = cast<MCDwarfCallFrameFragment>(this);
+    OS << "\n       ";
+    OS << " AddrDelta:" << CF->getAddrDelta();
+    break;
+  }
   case MCFragment::FT_LEB: {
     const MCLEBFragment *LF = cast<MCLEBFragment>(this);
     OS << "\n       ";
index 6e59a58b04da41351af50a8f00bc552a4c0eb5d5..08d327ae8b83cb8d9cffd8220e28cd9e9e2a814d 100644 (file)
@@ -460,12 +460,7 @@ static void EmitFrameMoves(MCStreamer &streamer,
     if (BaseLabel && Label) {
       MCSymbol *ThisSym = Label;
       if (ThisSym != BaseLabel) {
-        // FIXME: We should relax this instead of using a DW_CFA_advance_loc4
-        // for every address change!
-        streamer.EmitIntValue(dwarf::DW_CFA_advance_loc4, 1);
-        const MCExpr *Length = MakeStartMinusEndExpr(streamer, *BaseLabel,
-                                                     *ThisSym, 0);
-        streamer.EmitValue(Length, 4);
+        streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym);
         BaseLabel = ThisSym;
       }
     }
@@ -748,3 +743,30 @@ void MCDwarfFrameEmitter::Emit(MCStreamer &streamer) {
   if (fdeEnd)
     streamer.EmitLabel(fdeEnd);
 }
+
+void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &Streamer,
+                                         uint64_t AddrDelta) {
+  SmallString<256> Tmp;
+  raw_svector_ostream OS(Tmp);
+  MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OS);
+  Streamer.EmitBytes(OS.str(), /*AddrSpace=*/0);
+}
+
+void MCDwarfFrameEmitter::EncodeAdvanceLoc(uint64_t AddrDelta,
+                                           raw_ostream &OS) {
+  // FIXME: Assumes the code alignment factor is 1.
+  if (isUIntN(6, AddrDelta)) {
+    uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
+    OS << Opcode;
+  } else if (isUInt<8>(AddrDelta)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc1);
+    OS << uint8_t(AddrDelta);
+  } else if (isUInt<16>(AddrDelta)) {
+    OS << uint8_t(dwarf::DW_CFA_advance_loc2);
+    OS << uint16_t(AddrDelta);
+  } else {
+    assert(isUInt<32>(AddrDelta));
+    OS << uint8_t(dwarf::DW_CFA_advance_loc4);
+    OS << uint32_t(AddrDelta);
+  }
+}
index af102ecf78a7d2201716e64ae5a648cf74e81341..b428e8747b61c45a6a909e02643feb997125a2c2 100644 (file)
@@ -190,6 +190,28 @@ void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) {
   getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, IF->getFixups());
 }
 
+static const MCExpr *BuildSymbolDiff(MCContext &Context,
+                                     const MCSymbol *A, const MCSymbol *B) {
+  MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+  const MCExpr *ARef =
+    MCSymbolRefExpr::Create(A, Variant, Context);
+  const MCExpr *BRef =
+    MCSymbolRefExpr::Create(B, Variant, Context);
+  const MCExpr *AddrDelta =
+    MCBinaryExpr::Create(MCBinaryExpr::Sub, ARef, BRef, Context);
+  return AddrDelta;
+}
+
+static const MCExpr *ForceExpAbs(MCObjectStreamer *Streamer,
+                                  MCContext &Context, const MCExpr* Expr) {
+ if (Context.getAsmInfo().hasAggressiveSymbolFolding())
+   return Expr;
+
+ MCSymbol *ABS = Context.CreateTempSymbol();
+ Streamer->EmitAssignment(ABS, Expr);
+ return MCSymbolRefExpr::Create(ABS, Context);
+}
+
 void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
                                                 const MCSymbol *LastLabel,
                                                 const MCSymbol *Label) {
@@ -198,27 +220,28 @@ void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta,
     EmitDwarfSetLineAddr(LineDelta, Label, PointerSize);
     return;
   }
-  MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
-  const MCExpr *LabelRef =
-    MCSymbolRefExpr::Create(Label, Variant, getContext());
-  const MCExpr *LastLabelRef =
-    MCSymbolRefExpr::Create(LastLabel, Variant, getContext());
-  const MCExpr *AddrDelta =
-    MCBinaryExpr::Create(MCBinaryExpr::Sub, LabelRef, LastLabelRef,
-                         getContext());
+  const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel);
   int64_t Res;
   if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) {
     MCDwarfLineAddr::Emit(this, LineDelta, Res);
     return;
   }
-  if (!getContext().getAsmInfo().hasAggressiveSymbolFolding()) {
-    MCSymbol *ABS = getContext().CreateTempSymbol();
-    EmitAssignment(ABS, AddrDelta);
-    AddrDelta = MCSymbolRefExpr::Create(ABS, getContext());
-  }
+  AddrDelta = ForceExpAbs(this, getContext(), AddrDelta);
   new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, getCurrentSectionData());
 }
 
+void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
+                                                 const MCSymbol *Label) {
+  const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel);
+  int64_t Res;
+  if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) {
+    MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res);
+    return;
+  }
+  AddrDelta = ForceExpAbs(this, getContext(), AddrDelta);
+  new MCDwarfCallFrameFragment(*AddrDelta, getCurrentSectionData());
+}
+
 void MCObjectStreamer::EmitValueToOffset(const MCExpr *Offset,
                                         unsigned char Value) {
   new MCOrgFragment(*Offset, Value, getCurrentSectionData());
index b75cc12eafccced155285f5c329d79dd1b094cdf..efefb8789dcea307f85deae6dab503a58fcdb6f7 100644 (file)
@@ -10,21 +10,18 @@ f:
        ret
        .cfi_endproc
 
-// FIXME: This is a correct but really inefficient coding since
-// we use a CFA_advance_loc4 for every address change!
-
 // CHECK:      # Section 0x00000004
 // CHECK-NEXT: (('sh_name', 0x00000012) # '.eh_frame'
 // CHECK-NEXT:  ('sh_type', 0x00000001)
 // CHECK-NEXT:  ('sh_flags', 0x00000002)
 // CHECK-NEXT:  ('sh_addr', 0x00000000)
 // CHECK-NEXT:  ('sh_offset', 0x00000050)
-// CHECK-NEXT:  ('sh_size', 0x00000038)
+// CHECK-NEXT:  ('sh_size', 0x00000030)
 // CHECK-NEXT:  ('sh_link', 0x00000000)
 // CHECK-NEXT:  ('sh_info', 0x00000000)
 // CHECK-NEXT:  ('sh_addralign', 0x00000008)
 // CHECK-NEXT:  ('sh_entsize', 0x00000000)
-// CHECK-NEXT:  ('_section_data', '14000000 00000000 017a5200 01781001 1b0c0708 90010000 1c000000 1c000000 00000000 0a000000 00040400 00000e10 04050000 000e0800')
+// CHECK-NEXT:  ('_section_data', '14000000 00000000 017a5200 01781001 1b0c0708 90010000 14000000 1c000000 00000000 0a000000 00440e10 450e0800')
 // CHECK-NEXT: ),
 
 // CHECK:       # Section 0x00000008
@@ -32,7 +29,7 @@ f:
 // CHECK-NEXT:  ('sh_type', 0x00000004)
 // CHECK-NEXT:  ('sh_flags', 0x00000000)
 // CHECK-NEXT:  ('sh_addr', 0x00000000)
-// CHECK-NEXT:  ('sh_offset', 0x00000168)
+// CHECK-NEXT:  ('sh_offset', 0x00000160)
 // CHECK-NEXT:  ('sh_size', 0x00000018)
 // CHECK-NEXT:  ('sh_link', 0x00000006)
 // CHECK-NEXT:  ('sh_info', 0x00000004)