Emit .eh_frame with relocations to functions, rather than sections
authorOliver Stannard <oliver.stannard@arm.com>
Mon, 3 Nov 2014 12:02:51 +0000 (12:02 +0000)
committerOliver Stannard <oliver.stannard@arm.com>
Mon, 3 Nov 2014 12:02:51 +0000 (12:02 +0000)
When LLVM emits DWARF call frame information, it currently creates a local,
section-relative symbol in the code section, which is pointed to by a
relocation on the .eh_frame section. However, for C++ we emit some functions in
section groups, and the SysV ABI has some rules to make it easier to remove
these sections
(http://www.sco.com/developers/gabi/latest/ch4.sheader.html#section_group_rules):

  A symbol table entry with STB_LOCAL binding that is defined relative to one
  of a group's sections, and that is contained in a symbol table section that is
  not part of the group, must be discarded if the group members are discarded.
  References to this symbol table entry from outside the group are not allowed.

This means that we need to use the function symbol for the relocation, not a
temporary symbol.

There was a comment in the code claiming that the local symbol was used to
avoid creating a relocation, but a relocation must be created anyway as the
code and CFI are in different sections.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221150 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/MC/MCObjectStreamer.h
include/llvm/MC/MCStreamer.h
lib/CodeGen/AsmPrinter/ARMException.cpp
lib/CodeGen/AsmPrinter/DwarfCFIException.cpp
lib/MC/MCAsmStreamer.cpp
lib/MC/MCObjectStreamer.cpp
lib/MC/MCParser/AsmParser.cpp
lib/MC/MCStreamer.cpp
test/DebugInfo/AArch64/eh_frame.s
test/DebugInfo/AArch64/eh_frame_personality.ll

index 0866ff5a9fc089020bce6633bdc08de0f9c65851..71354477b33149c91e587b66f17931be31a55748 100644 (file)
@@ -41,7 +41,8 @@ class MCObjectStreamer : public MCStreamer {
   SmallVector<MCSymbolData *, 2> PendingLabels;
 
   virtual void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo&) = 0;
-  void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+  void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame,
+                            MCSymbol *FuncSym) override;
   void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
 
   // If any labels have been emitted but not assigned fragments, ensure that
index 5cded5cfff9005ffbd126bcf20d74eac4e2ab92c..7303bc9dc6c9a9d8bb3a3dce39047dbf40cb0d33 100644 (file)
@@ -198,7 +198,7 @@ class MCStreamer {
 protected:
   MCStreamer(MCContext &Ctx);
 
-  virtual void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame);
+  virtual void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame, MCSymbol *FuncSym);
   virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &CurFrame);
 
   WinEH::FrameInfo *getCurrentWinFrameInfo() {
@@ -661,7 +661,7 @@ public:
 
   virtual MCSymbol *getDwarfLineTableSymbol(unsigned CUID);
   virtual void EmitCFISections(bool EH, bool Debug);
-  void EmitCFIStartProc(bool IsSimple);
+  void EmitCFIStartProc(bool IsSimple, MCSymbol *FuncSym);
   void EmitCFIEndProc();
   virtual void EmitCFIDefCfa(int64_t Register, int64_t Offset);
   virtual void EmitCFIDefCfaOffset(int64_t Offset);
index 251f5effd6b4d3cb043bebc21732824c997841e9..e79ede9a5ae829552fb8d4bda83dcc3d95666299 100644 (file)
@@ -66,7 +66,7 @@ void ARMException::beginFunction(const MachineFunction *MF) {
          "non-EH CFI not yet supported in prologue with EHABI lowering");
   if (MoveType == AsmPrinter::CFI_M_Debug) {
     shouldEmitCFI = true;
-    Asm->OutStreamer.EmitCFIStartProc(false);
+    Asm->OutStreamer.EmitCFIStartProc(false, Asm->CurrentFnSym);
   }
 }
 
index 74215aa695ddbf487f872cc3ae7a621502985539..b8051fee9fa840c2d6de711bae905ef9a208d3c9 100644 (file)
@@ -102,7 +102,7 @@ void DwarfCFIException::beginFunction(const MachineFunction *MF) {
   if (!shouldEmitPersonality && !shouldEmitMoves)
     return;
 
-  Asm->OutStreamer.EmitCFIStartProc(/*IsSimple=*/false);
+  Asm->OutStreamer.EmitCFIStartProc(/*IsSimple=*/false, Asm->CurrentFnSym);
 
   // Indicate personality routine, if any.
   if (!shouldEmitPersonality)
index f60c7fc50415ffa4840656a8e131bc9800c7b013..9e100333e9bfa35356ea5c01d35b37b05f042b82 100644 (file)
@@ -54,7 +54,8 @@ private:
   unsigned UseDwarfDirectory : 1;
 
   void EmitRegisterName(int64_t Register);
-  void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+  void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame,
+                            MCSymbol *FuncSym) override;
   void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
 
 public:
@@ -925,7 +926,8 @@ void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) {
   EmitEOL();
 }
 
-void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame,
+                                         MCSymbol *FuncSym) {
   OS << "\t.cfi_startproc";
   if (Frame.IsSimple)
     OS << " simple";
index 21e68678e75be9713578c7e965eecb57a5728fd3..17371a285089f578ee7c484d1f64d9d838e673ce 100644 (file)
@@ -128,10 +128,13 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
   DF->getContents().resize(DF->getContents().size() + Size, 0);
 }
 
-void MCObjectStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
-  // We need to create a local symbol to avoid relocations.
-  Frame.Begin = getContext().CreateTempSymbol();
-  EmitLabel(Frame.Begin);
+void MCObjectStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame,
+                                            MCSymbol *FuncSym) {
+  if (!FuncSym) {
+    FuncSym = getContext().CreateTempSymbol();
+    EmitLabel(FuncSym);
+  }
+  Frame.Begin = FuncSym;
 }
 
 void MCObjectStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
index de7d96129f18e3bb71e75a6953f04197149b536e..5a56094a3c75a2d5b6cc0133df784c9c4de47ba8 100644 (file)
@@ -172,6 +172,9 @@ private:
   /// \brief Are we parsing ms-style inline assembly?
   bool ParsingInlineAsm;
 
+  /// \brief The last symbol we emitted, used for call frame information.
+  MCSymbol *LastFuncSymbol;
+
 public:
   AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
             const MCAsmInfo &MAI);
@@ -491,7 +494,8 @@ AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out,
     : Lexer(_MAI), Ctx(_Ctx), Out(_Out), MAI(_MAI), SrcMgr(_SM),
       PlatformParser(nullptr), CurBuffer(_SM.getMainFileID()),
       MacrosEnabledFlag(true), HadError(false), CppHashLineNumber(0),
-      AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false) {
+      AssemblerDialect(~0U), IsDarwin(false), ParsingInlineAsm(false),
+      LastFuncSymbol(nullptr) {
   // Save the old handler.
   SavedDiagHandler = SrcMgr.getDiagHandler();
   SavedDiagContext = SrcMgr.getDiagContext();
@@ -1305,6 +1309,9 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
     if (!ParsingInlineAsm)
       Out.EmitLabel(Sym);
 
+    // Record the symbol, so that it can be used for call frame information
+    LastFuncSymbol = Sym;
+
     // If we are generating dwarf for assembly source files then gather the
     // info to make a dwarf label entry for this label if needed.
     if (getContext().getGenDwarfForAssembly())
@@ -2961,7 +2968,7 @@ bool AsmParser::parseDirectiveCFIStartProc() {
     if (parseIdentifier(Simple) || Simple != "simple")
       return TokError("unexpected token in .cfi_startproc directive");
 
-  getStreamer().EmitCFIStartProc(!Simple.empty());
+  getStreamer().EmitCFIStartProc(!Simple.empty(), LastFuncSymbol);
   return false;
 }
 
index f11ee669b4b6837c5634e3ac469ecb37ce7e3be5..23e816c24bf808692336cf5c9555c707cbf295fb 100644 (file)
@@ -211,14 +211,14 @@ void MCStreamer::EmitCFISections(bool EH, bool Debug) {
   assert(EH || Debug);
 }
 
-void MCStreamer::EmitCFIStartProc(bool IsSimple) {
+void MCStreamer::EmitCFIStartProc(bool IsSimple, MCSymbol *FuncSym) {
   MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
   if (CurFrame && !CurFrame->End)
     report_fatal_error("Starting a frame before finishing the previous one!");
 
   MCDwarfFrameInfo Frame;
   Frame.IsSimple = IsSimple;
-  EmitCFIStartProcImpl(Frame);
+  EmitCFIStartProcImpl(Frame, FuncSym);
 
   const MCAsmInfo* MAI = Context.getAsmInfo();
   if (MAI) {
@@ -233,8 +233,8 @@ void MCStreamer::EmitCFIStartProc(bool IsSimple) {
   DwarfFrameInfos.push_back(Frame);
 }
 
-void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
-}
+void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame,
+                                      MCSymbol *FuncSym) {}
 
 void MCStreamer::EmitCFIEndProc() {
   EnsureValidDwarfFrame();
index 12a58961d7176a0754bb20c5bd55b3f6b33a159e..75b036eac26b858168b1251360eb2b3f553ca460 100644 (file)
@@ -1,5 +1,6 @@
 // RUN: llvm-mc -triple aarch64-none-linux-gnu -filetype=obj %s -o %t
-// RUN: llvm-objdump -s %t | FileCheck %s
+// RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=CHECK
+// RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
         .text
         .globl foo
         .type foo,@function
@@ -46,3 +47,11 @@ foo:
 // 00000000: PC begin for this FDE is at 00000000 (relocation is applied here)
 // 04000000: FDE applies up to PC begin+0x14
 // 00: Augmentation string length 0 for this FDE
+
+
+// Check the relocations applied to the .eh_frame section.
+// These must not contain section-relative relocations to a section which
+// is part of a group, as it could be removed.
+// RELOC: Section ({{[0-9]+}}) .rela.eh_frame {
+// RELOC-NEXT:   0x{{[0-9A-F]+}} R_AARCH64_PREL32 foo 0x0
+// RELOC-NEXT: }
index 51d6bf80b950d3e11a4f3cfecd0b3c16688b6793..0cc53a810e976882fa91f9f3146e7ace3fc97372 100644 (file)
@@ -1,5 +1,6 @@
 ; RUN: llc -verify-machineinstrs -mtriple=aarch64-none-linux-gnu %s -filetype=obj -o %t
-; RUN: llvm-objdump -s %t | FileCheck %s
+; RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=CHECK
+; RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
 
 declare i32 @__gxx_personality_v0(...)
 
@@ -44,3 +45,12 @@ clean:
 ; 00: Second part of aug (language-specific data): absolute pointer format used
 ; 1b: pointer format: pc-relative signed 4-byte. Just like GNU.
 ; 0c 1f 00: Initial instructions ("DW_CFA_def_cfa x31 ofs 0" in this case)
+
+; Check the relocations applied to the .eh_frame section.
+; These must not contain section-relative relocations to a section which
+; is part of a group, as it could be removed.
+; RELOC: Section ({{[0-9]+}}) .rela.eh_frame {
+; RELOC-NEXT:   0x{{[0-9A-F]+}} R_AARCH64_ABS64 __gxx_personality_v0 0x0
+; RELOC-NEXT:   0x{{[0-9A-F]+}} R_AARCH64_PREL32 foo 0x0
+; RELOC-NEXT:   0x{{[0-9A-F]+}} R_AARCH64_ABS64 .gcc_except_table 0x0
+; RELOC-NEXT: }