aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2011-02-16 01:08:29 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2011-02-16 01:08:29 +0000
commit7768a9dce14431018133cd586f5c8ce3e057f069 (patch)
tree96d6d88654a2520802874c021b320394bfe2e1ff
parente32effb02f28025bcbb1eb6b673f46f8d072627b (diff)
downloadexternal_llvm-7768a9dce14431018133cd586f5c8ce3e057f069.zip
external_llvm-7768a9dce14431018133cd586f5c8ce3e057f069.tar.gz
external_llvm-7768a9dce14431018133cd586f5c8ce3e057f069.tar.bz2
Add support for pushsection and popsection. Patch by Joerg Sonnenberger.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@125629 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/MC/MCObjectStreamer.h2
-rw-r--r--include/llvm/MC/MCStreamer.h69
-rw-r--r--lib/MC/MCAsmStreamer.cpp20
-rw-r--r--lib/MC/MCELFStreamer.cpp8
-rw-r--r--lib/MC/MCLoggingStreamer.cpp7
-rw-r--r--lib/MC/MCMachOStreamer.cpp2
-rw-r--r--lib/MC/MCNullStreamer.cpp8
-rw-r--r--lib/MC/MCObjectStreamer.cpp11
-rw-r--r--lib/MC/MCParser/ELFAsmParser.cpp30
-rw-r--r--lib/MC/MCPureStreamer.cpp4
-rw-r--r--lib/MC/MCStreamer.cpp5
-rw-r--r--lib/Target/PTX/PTXMCAsmStreamer.cpp19
-rw-r--r--test/MC/AsmParser/section.s107
13 files changed, 226 insertions, 66 deletions
diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h
index f6fd9d7..833341e 100644
--- a/include/llvm/MC/MCObjectStreamer.h
+++ b/include/llvm/MC/MCObjectStreamer.h
@@ -64,7 +64,7 @@ public:
virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0);
virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0);
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
- virtual void SwitchSection(const MCSection *Section);
+ virtual void ChangeSection(const MCSection *Section);
virtual void EmitInstruction(const MCInst &Inst);
virtual void EmitInstToFragment(const MCInst &Inst);
virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value);
diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h
index 1be2dc6..fc2451f 100644
--- a/include/llvm/MC/MCStreamer.h
+++ b/include/llvm/MC/MCStreamer.h
@@ -14,6 +14,7 @@
#ifndef LLVM_MC_MCSTREAMER_H
#define LLVM_MC_MCSTREAMER_H
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/MC/MCDirectives.h"
#include "llvm/MC/MCDwarf.h"
@@ -56,16 +57,16 @@ namespace llvm {
MCDwarfFrameInfo *getCurrentFrameInfo();
void EnsureValidFrame();
- protected:
- MCStreamer(MCContext &Ctx);
+ /// CurSectionStack - This is stack of CurSection values saved by
+ /// PushSection.
+ SmallVector<const MCSection *, 4> CurSectionStack;
- /// CurSection - This is the current section code is being emitted to, it is
- /// kept up to date by SwitchSection.
- const MCSection *CurSection;
+ /// PrevSectionStack - This is stack of PrevSection values saved by
+ /// PushSection.
+ SmallVector<const MCSection *, 4> PrevSectionStack;
- /// PrevSection - This is the previous section code is being emitted to, it
- /// is kept up to date by SwitchSection.
- const MCSection *PrevSection;
+ protected:
+ MCStreamer(MCContext &Ctx);
public:
virtual ~MCStreamer();
@@ -115,17 +116,63 @@ namespace llvm {
/// getCurrentSection - Return the current section that the streamer is
/// emitting code to.
- const MCSection *getCurrentSection() const { return CurSection; }
+ const MCSection *getCurrentSection() const {
+ if (!CurSectionStack.empty())
+ return CurSectionStack.back();
+ return NULL;
+ }
/// getPreviousSection - Return the previous section that the streamer is
/// emitting code to.
- const MCSection *getPreviousSection() const { return PrevSection; }
+ const MCSection *getPreviousSection() const {
+ if (!PrevSectionStack.empty())
+ return PrevSectionStack.back();
+ return NULL;
+ }
+
+ /// ChangeSection - Update streamer for a new active section.
+ ///
+ /// This is called by PopSection and SwitchSection, if the current
+ /// section changes.
+ virtual void ChangeSection(const MCSection *) = 0;
+
+ /// pushSection - Save the current and previous section on the
+ /// section stack.
+ void PushSection() {
+ PrevSectionStack.push_back(getPreviousSection());
+ CurSectionStack.push_back(getCurrentSection());
+ }
+
+ /// popSection - Restore the current and previous section from
+ /// the section stack. Calls ChangeSection as needed.
+ ///
+ /// Returns false if the stack was empty.
+ bool PopSection() {
+ if (PrevSectionStack.size() <= 1)
+ return false;
+ assert(CurSectionStack.size() > 1);
+ PrevSectionStack.pop_back();
+ const MCSection *oldSection = CurSectionStack.pop_back_val();
+ const MCSection *curSection = CurSectionStack.back();
+
+ if (oldSection != curSection)
+ ChangeSection(curSection);
+ return true;
+ }
/// SwitchSection - Set the current section where code is being emitted to
/// @p Section. This is required to update CurSection.
///
/// This corresponds to assembler directives like .section, .text, etc.
- virtual void SwitchSection(const MCSection *Section) = 0;
+ void SwitchSection(const MCSection *Section) {
+ assert(Section && "Cannot switch to a null section!");
+ const MCSection *curSection = CurSectionStack.back();
+ PrevSectionStack.back() = curSection;
+ if (Section != curSection) {
+ CurSectionStack.back() = Section;
+ ChangeSection(Section);
+ }
+ }
/// InitSections - Create the default sections and set the initial one.
virtual void InitSections() = 0;
diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp
index 6aabfe1..8d06982 100644
--- a/lib/MC/MCAsmStreamer.cpp
+++ b/lib/MC/MCAsmStreamer.cpp
@@ -107,7 +107,7 @@ public:
/// @name MCStreamer Interface
/// @{
- virtual void SwitchSection(const MCSection *Section);
+ virtual void ChangeSection(const MCSection *Section);
virtual void InitSections() {
// FIXME, this is MachO specific, but the testsuite
@@ -254,23 +254,19 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}
-void MCAsmStreamer::SwitchSection(const MCSection *Section) {
+void MCAsmStreamer::ChangeSection(const MCSection *Section) {
assert(Section && "Cannot switch to a null section!");
- if (Section != CurSection) {
- PrevSection = CurSection;
- CurSection = Section;
- Section->PrintSwitchToSection(MAI, OS);
- }
+ Section->PrintSwitchToSection(MAI, OS);
}
void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
- assert(CurSection && "Cannot emit before setting section!");
+ assert(getCurrentSection() && "Cannot emit before setting section!");
OS << *Symbol << MAI.getLabelSuffix();
EmitEOL();
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
}
void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
@@ -486,7 +482,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
if (Data.empty()) return;
if (Data.size() == 1) {
@@ -517,7 +513,7 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size,
void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
bool isPCRel, unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
assert(!isPCRel && "Cannot emit pc relative relocations!");
const char *Directive = 0;
switch (Size) {
@@ -864,7 +860,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) {
}
void MCAsmStreamer::EmitInstruction(const MCInst &Inst) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
if (!UseLoc)
MCLineEntry::Make(this, getCurrentSection());
diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp
index ac31057..e49074d 100644
--- a/lib/MC/MCELFStreamer.cpp
+++ b/lib/MC/MCELFStreamer.cpp
@@ -80,12 +80,12 @@ public:
/// @{
virtual void InitSections();
+ virtual void ChangeSection(const MCSection *Section);
virtual void EmitLabel(MCSymbol *Symbol);
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag);
virtual void EmitThumbFunc(MCSymbol *Func);
virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value);
virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol);
- virtual void SwitchSection(const MCSection *Section);
virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute);
virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
assert(0 && "ELF doesn't support this directive");
@@ -222,11 +222,11 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
Symbol->setVariableValue(AddValueSymbols(Value));
}
-void MCELFStreamer::SwitchSection(const MCSection *Section) {
+void MCELFStreamer::ChangeSection(const MCSection *Section) {
const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup();
if (Grp)
getAssembler().getOrCreateSymbolData(*Grp);
- this->MCObjectStreamer::SwitchSection(Section);
+ this->MCObjectStreamer::ChangeSection(Section);
}
void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
@@ -411,7 +411,7 @@ void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment,
// entry in the module's symbol table (the first being the null symbol).
void MCELFStreamer::EmitFileDirective(StringRef Filename) {
MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename);
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
Symbol->setAbsolute();
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp
index d947481..012c7f6 100644
--- a/lib/MC/MCLoggingStreamer.cpp
+++ b/lib/MC/MCLoggingStreamer.cpp
@@ -48,10 +48,9 @@ public:
return Child->AddBlankLine();
}
- virtual void SwitchSection(const MCSection *Section) {
- CurSection = Section;
- LogCall("SwitchSection");
- return Child->SwitchSection(Section);
+ virtual void ChangeSection(const MCSection *Section) {
+ LogCall("ChangeSection");
+ return Child->ChangeSection(Section);
}
virtual void InitSections() {
diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp
index 7e1cda2..d1f9f5c 100644
--- a/lib/MC/MCMachOStreamer.cpp
+++ b/lib/MC/MCMachOStreamer.cpp
@@ -105,7 +105,7 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
// isSymbolLinkerVisible uses the section.
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
// We have to create a new fragment if this is an atom defining symbol,
// fragments cannot span atoms.
if (getAssembler().isSymbolLinkerVisible(*Symbol))
diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp
index b9393ff..08ddf01 100644
--- a/lib/MC/MCNullStreamer.cpp
+++ b/lib/MC/MCNullStreamer.cpp
@@ -28,15 +28,13 @@ namespace {
virtual void InitSections() {
}
- virtual void SwitchSection(const MCSection *Section) {
- PrevSection = CurSection;
- CurSection = Section;
+ virtual void ChangeSection(const MCSection *Section) {
}
virtual void EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
- assert(CurSection && "Cannot emit before setting section!");
- Symbol->setSection(*CurSection);
+ assert(getCurrentSection() && "Cannot emit before setting section!");
+ Symbol->setSection(*getCurrentSection());
}
virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {}
diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp
index ecd7257..0358266 100644
--- a/lib/MC/MCObjectStreamer.cpp
+++ b/lib/MC/MCObjectStreamer.cpp
@@ -101,9 +101,9 @@ void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
void MCObjectStreamer::EmitLabel(MCSymbol *Symbol) {
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
- assert(CurSection && "Cannot emit before setting section!");
+ assert(getCurrentSection() && "Cannot emit before setting section!");
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
@@ -142,14 +142,9 @@ void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias,
report_fatal_error("This file format doesn't support weak aliases.");
}
-void MCObjectStreamer::SwitchSection(const MCSection *Section) {
+void MCObjectStreamer::ChangeSection(const MCSection *Section) {
assert(Section && "Cannot switch to a null section!");
- // If already in this section, then this is a noop.
- if (Section == CurSection) return;
-
- PrevSection = CurSection;
- CurSection = Section;
CurSectionData = &getAssembler().getOrCreateSectionData(*Section);
}
diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp
index 7b88ea2..bfaf36a 100644
--- a/lib/MC/MCParser/ELFAsmParser.cpp
+++ b/lib/MC/MCParser/ELFAsmParser.cpp
@@ -49,6 +49,8 @@ public:
AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local");
AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame");
AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section");
+ AddDirectiveHandler<&ELFAsmParser::ParseDirectivePushSection>(".pushsection");
+ AddDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection");
AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size");
AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous");
AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type");
@@ -115,6 +117,8 @@ public:
ELF::SHF_WRITE,
SectionKind::getDataRel());
}
+ bool ParseDirectivePushSection(StringRef, SMLoc);
+ bool ParseDirectivePopSection(StringRef, SMLoc);
bool ParseDirectiveSection(StringRef, SMLoc);
bool ParseDirectiveSize(StringRef, SMLoc);
bool ParseDirectivePrevious(StringRef, SMLoc);
@@ -253,6 +257,23 @@ static int parseSectionFlags(StringRef flagsStr) {
return flags;
}
+bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) {
+ getStreamer().PushSection();
+
+ if (ParseDirectiveSection(s, loc)) {
+ getStreamer().PopSection();
+ return true;
+ }
+
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) {
+ if (!getStreamer().PopSection())
+ return TokError(".popsection without corresponding .pushsection");
+ return false;
+}
+
// FIXME: This is a work in progress.
bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
StringRef SectionName;
@@ -364,8 +385,9 @@ bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) {
const MCSection *PreviousSection = getStreamer().getPreviousSection();
- if (PreviousSection != NULL)
- getStreamer().SwitchSection(PreviousSection);
+ if (PreviousSection == NULL)
+ return TokError(".previous without corresponding .section");
+ getStreamer().SwitchSection(PreviousSection);
return false;
}
@@ -427,7 +449,6 @@ bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) {
Lex();
- const MCSection *OldSection = getStreamer().getCurrentSection();
const MCSection *Comment =
getContext().getELFSection(".comment", ELF::SHT_PROGBITS,
ELF::SHF_MERGE |
@@ -437,13 +458,14 @@ bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) {
static bool First = true;
+ getStreamer().PushSection();
getStreamer().SwitchSection(Comment);
if (First)
getStreamer().EmitIntValue(0, 1);
First = false;
getStreamer().EmitBytes(Data, 0);
getStreamer().EmitIntValue(0, 1);
- getStreamer().SwitchSection(OldSection);
+ getStreamer().PopSection();
return false;
}
diff --git a/lib/MC/MCPureStreamer.cpp b/lib/MC/MCPureStreamer.cpp
index 5341844..6098e6b 100644
--- a/lib/MC/MCPureStreamer.cpp
+++ b/lib/MC/MCPureStreamer.cpp
@@ -113,9 +113,9 @@ void MCPureStreamer::InitSections() {
void MCPureStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
- assert(CurSection && "Cannot emit before setting section!");
+ assert(getCurrentSection() && "Cannot emit before setting section!");
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp
index 1cb5165..3dcdba1 100644
--- a/lib/MC/MCStreamer.cpp
+++ b/lib/MC/MCStreamer.cpp
@@ -19,8 +19,9 @@
#include <cstdlib>
using namespace llvm;
-MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0),
- PrevSection(0) {
+MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx) {
+ PrevSectionStack.push_back(NULL);
+ CurSectionStack.push_back(NULL);
}
MCStreamer::~MCStreamer() {
diff --git a/lib/Target/PTX/PTXMCAsmStreamer.cpp b/lib/Target/PTX/PTXMCAsmStreamer.cpp
index fc3dd5f..0886ba8 100644
--- a/lib/Target/PTX/PTXMCAsmStreamer.cpp
+++ b/lib/Target/PTX/PTXMCAsmStreamer.cpp
@@ -100,8 +100,7 @@ public:
/// @name MCStreamer Interface
/// @{
- virtual void SwitchSection(const MCSection *Section);
-
+ virtual void ChangeSection(const MCSection *Section);
virtual void InitSections() {}
virtual void EmitLabel(MCSymbol *Symbol);
@@ -227,22 +226,18 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
}
-void PTXMCAsmStreamer::SwitchSection(const MCSection *Section) {
+void PTXMCAsmStreamer::ChangeSection(const MCSection *Section) {
assert(Section && "Cannot switch to a null section!");
- if (Section != CurSection) {
- PrevSection = CurSection;
- CurSection = Section;
- }
}
void PTXMCAsmStreamer::EmitLabel(MCSymbol *Symbol) {
assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
- assert(CurSection && "Cannot emit before setting section!");
+ assert(getCurrentSection() && "Cannot emit before setting section!");
OS << *Symbol << MAI.getLabelSuffix();
EmitEOL();
- Symbol->setSection(*CurSection);
+ Symbol->setSection(*getCurrentSection());
}
void PTXMCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {}
@@ -332,7 +327,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
}
void PTXMCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
if (Data.empty()) return;
if (Data.size() == 1) {
@@ -358,7 +353,7 @@ void PTXMCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
void PTXMCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
bool isPCRel, unsigned AddrSpace) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
assert(!isPCRel && "Cannot emit pc relative relocations!");
const char *Directive = 0;
switch (Size) {
@@ -502,7 +497,7 @@ bool PTXMCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo,
void PTXMCAsmStreamer::AddEncodingComment(const MCInst &Inst) {}
void PTXMCAsmStreamer::EmitInstruction(const MCInst &Inst) {
- assert(CurSection && "Cannot emit contents before setting section!");
+ assert(getCurrentSection() && "Cannot emit contents before setting section!");
// Show the encoding in a comment if we have a code emitter.
if (Emitter)
diff --git a/test/MC/AsmParser/section.s b/test/MC/AsmParser/section.s
new file mode 100644
index 0000000..414fc6d
--- /dev/null
+++ b/test/MC/AsmParser/section.s
@@ -0,0 +1,107 @@
+# RUN: llvm-mc -triple i386-pc-linux-gnu -filetype=obj -o %t %s
+# RUN: elf-dump --dump-section-data < %t | FileCheck %s
+.section test1
+.byte 1
+.section test2
+.byte 2
+.previous
+.byte 1
+.section test2
+.byte 2
+.previous
+.byte 1
+.section test1
+.byte 1
+.previous
+.byte 1
+.section test2
+.byte 2
+.pushsection test3
+.byte 3
+.pushsection test4
+.byte 4
+.pushsection test5
+.byte 5
+.popsection
+.byte 4
+.popsection
+.byte 3
+.popsection
+.byte 2
+.pushsection test3
+.byte 3
+.pushsection test4
+.byte 4
+.previous
+.byte 3
+.popsection
+.byte 3
+.previous
+.byte 2
+.section test1
+.byte 1
+.popsection
+.byte 2
+.previous
+.byte 1
+.previous
+# CHECK: (('sh_name', 0x00000012) # 'test1'
+# CHECK-NEXT: ('sh_type', 0x00000001)
+# CHECK-NEXT: ('sh_flags', 0x00000000)
+# CHECK-NEXT: ('sh_addr', 0x00000000)
+# CHECK-NEXT: ('sh_offset', 0x00000034)
+# CHECK-NEXT: ('sh_size', 0x00000007)
+# CHECK-NEXT: ('sh_link', 0x00000000)
+# CHECK-NEXT: ('sh_info', 0x00000000)
+# CHECK-NEXT: ('sh_addralign', 0x00000001)
+# CHECK-NEXT: ('sh_entsize', 0x00000000)
+# CHECK-NEXT: ('_section_data', '01010101 010101')
+# CHECK-NEXT: ),
+# CHECK: (('sh_name', 0x00000018) # 'test2'
+# CHECK-NEXT: ('sh_type', 0x00000001)
+# CHECK-NEXT: ('sh_flags', 0x00000000)
+# CHECK-NEXT: ('sh_addr', 0x00000000)
+# CHECK-NEXT: ('sh_offset', 0x0000003b)
+# CHECK-NEXT: ('sh_size', 0x00000006)
+# CHECK-NEXT: ('sh_link', 0x00000000)
+# CHECK-NEXT: ('sh_info', 0x00000000)
+# CHECK-NEXT: ('sh_addralign', 0x00000001)
+# CHECK-NEXT: ('sh_entsize', 0x00000000)
+# CHECK-NEXT: ('_section_data', '02020202 0202')
+# CHECK-NEXT: ),
+# CHECK: (('sh_name', 0x0000001e) # 'test3'
+# CHECK-NEXT: ('sh_type', 0x00000001)
+# CHECK-NEXT: ('sh_flags', 0x00000000)
+# CHECK-NEXT: ('sh_addr', 0x00000000)
+# CHECK-NEXT: ('sh_offset', 0x00000041)
+# CHECK-NEXT: ('sh_size', 0x00000005)
+# CHECK-NEXT: ('sh_link', 0x00000000)
+# CHECK-NEXT: ('sh_info', 0x00000000)
+# CHECK-NEXT: ('sh_addralign', 0x00000001)
+# CHECK-NEXT: ('sh_entsize', 0x00000000)
+# CHECK-NEXT: ('_section_data', '03030303 03')
+# CHECK-NEXT: ),
+# CHECK: (('sh_name', 0x00000024) # 'test4'
+# CHECK-NEXT: ('sh_type', 0x00000001)
+# CHECK-NEXT: ('sh_flags', 0x00000000)
+# CHECK-NEXT: ('sh_addr', 0x00000000)
+# CHECK-NEXT: ('sh_offset', 0x00000046)
+# CHECK-NEXT: ('sh_size', 0x00000003)
+# CHECK-NEXT: ('sh_link', 0x00000000)
+# CHECK-NEXT: ('sh_info', 0x00000000)
+# CHECK-NEXT: ('sh_addralign', 0x00000001)
+# CHECK-NEXT: ('sh_entsize', 0x00000000)
+# CHECK-NEXT: ('_section_data', '040404')
+# CHECK-NEXT: ),
+# CHECK: (('sh_name', 0x0000002a) # 'test5'
+# CHECK-NEXT: ('sh_type', 0x00000001)
+# CHECK-NEXT: ('sh_flags', 0x00000000)
+# CHECK-NEXT: ('sh_addr', 0x00000000)
+# CHECK-NEXT: ('sh_offset', 0x00000049)
+# CHECK-NEXT: ('sh_size', 0x00000001)
+# CHECK-NEXT: ('sh_link', 0x00000000)
+# CHECK-NEXT: ('sh_info', 0x00000000)
+# CHECK-NEXT: ('sh_addralign', 0x00000001)
+# CHECK-NEXT: ('sh_entsize', 0x00000000)
+# CHECK-NEXT: ('_section_data', '05')
+# CHECK-NEXT: ),