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
This commit is contained in:
Rafael Espindola 2011-02-16 01:08:29 +00:00
parent e32effb02f
commit 7768a9dce1
13 changed files with 226 additions and 66 deletions

View File

@ -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);

View File

@ -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,17 +57,17 @@ namespace llvm {
MCDwarfFrameInfo *getCurrentFrameInfo();
void EnsureValidFrame();
/// CurSectionStack - This is stack of CurSection values saved by
/// PushSection.
SmallVector<const MCSection *, 4> CurSectionStack;
/// PrevSectionStack - This is stack of PrevSection values saved by
/// PushSection.
SmallVector<const MCSection *, 4> PrevSectionStack;
protected:
MCStreamer(MCContext &Ctx);
/// CurSection - This is the current section code is being emitted to, it is
/// kept up to date by SwitchSection.
const MCSection *CurSection;
/// PrevSection - This is the previous section code is being emitted to, it
/// is kept up to date by SwitchSection.
const MCSection *PrevSection;
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;

View File

@ -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());

View File

@ -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);

View File

@ -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() {

View File

@ -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))

View File

@ -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) {}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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() {

View File

@ -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)

107
test/MC/AsmParser/section.s Normal file
View File

@ -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: ),