diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2010-12-28 05:39:27 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2010-12-28 05:39:27 +0000 |
commit | 245a1e20419aa5a3c833d7a8e89168e19d5f4d2c (patch) | |
tree | 1a10fd4b3e598e4457f2db8f82f92f4a6b47186e | |
parent | 5bba08425374ca36fe5fbc7423ce1a09858e4097 (diff) |
Relax address updates in the eh_frame section.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122591 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/MC/MCAssembler.h | 33 | ||||
-rw-r--r-- | include/llvm/MC/MCDwarf.h | 3 | ||||
-rw-r--r-- | include/llvm/MC/MCObjectStreamer.h | 2 | ||||
-rw-r--r-- | include/llvm/MC/MCStreamer.h | 4 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 40 | ||||
-rw-r--r-- | lib/MC/MCDwarf.cpp | 34 | ||||
-rw-r--r-- | lib/MC/MCObjectStreamer.cpp | 49 | ||||
-rw-r--r-- | test/MC/ELF/cfi-def-cfa-offset.s | 9 |
8 files changed, 145 insertions, 29 deletions
diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 65f01e7772..79d2c8ea41 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -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); diff --git a/include/llvm/MC/MCDwarf.h b/include/llvm/MC/MCDwarf.h index 26c28294ab..00b94c9e6a 100644 --- a/include/llvm/MC/MCDwarf.h +++ b/include/llvm/MC/MCDwarf.h @@ -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 diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 17ba09e3a0..f6fd9d73c7 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -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(); /// @} diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index ef2238da14..345f40109f 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -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); diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 030ff98739..5b291490f7 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -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 "; diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 6e59a58b04..08d327ae8b 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -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); + } +} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index af102ecf78..b428e8747b 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -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()); diff --git a/test/MC/ELF/cfi-def-cfa-offset.s b/test/MC/ELF/cfi-def-cfa-offset.s index b75cc12eaf..efefb8789d 100644 --- a/test/MC/ELF/cfi-def-cfa-offset.s +++ b/test/MC/ELF/cfi-def-cfa-offset.s @@ -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) |