From a6d343a688073664b3a80aa117e0d3cbecf28014 Mon Sep 17 00:00:00 2001 From: Nico Rieck Date: Thu, 4 Jul 2013 21:32:07 +0000 Subject: [PATCH] MC: Add .section directive to COFF Supports GAS flags "abdnrswxy". No support for alignment or subsections. Fixes PR16366. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@185669 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/MC/MCParser/COFFAsmParser.cpp | 172 +++++++++++++++++++++++++++ test/MC/COFF/section-invalid-flags.s | 8 ++ test/MC/COFF/section.s | 170 ++++++++++++++++++++++++++ test/MC/COFF/seh-section.s | 2 - 4 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 test/MC/COFF/section-invalid-flags.s create mode 100644 test/MC/COFF/section.s diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp index ad8f84c843a..c2a22619db2 100644 --- a/lib/MC/MCParser/COFFAsmParser.cpp +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -35,6 +35,9 @@ class COFFAsmParser : public MCAsmParserExtension { unsigned Characteristics, SectionKind Kind); + bool ParseSectionName(StringRef &SectionName); + bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags); + virtual void Initialize(MCAsmParser &Parser) { // Call the base implementation. MCAsmParserExtension::Initialize(Parser); @@ -42,6 +45,7 @@ class COFFAsmParser : public MCAsmParserExtension { addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); @@ -100,6 +104,7 @@ class COFFAsmParser : public MCAsmParserExtension { SectionKind::getBSS()); } + bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveDef(StringRef, SMLoc); bool ParseDirectiveScl(StringRef, SMLoc); bool ParseDirectiveType(StringRef, SMLoc); @@ -130,6 +135,119 @@ public: } // end annonomous namespace. +static SectionKind computeSectionKind(unsigned Flags) { + if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE) + return SectionKind::getText(); + if (Flags & COFF::IMAGE_SCN_MEM_READ && + (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0) + return SectionKind::getReadOnly(); + return SectionKind::getDataRel(); +} + +bool COFFAsmParser::ParseSectionFlags(StringRef FlagsString, unsigned* Flags) { + enum { + None = 0, + Alloc = 1 << 0, + Code = 1 << 1, + Load = 1 << 2, + InitData = 1 << 3, + Shared = 1 << 4, + NoLoad = 1 << 5, + NoRead = 1 << 6, + NoWrite = 1 << 7 + }; + + bool ReadOnlyRemoved = false; + unsigned SecFlags = None; + + for (unsigned i = 0; i < FlagsString.size(); ++i) { + switch (FlagsString[i]) { + case 'a': + // Ignored. + break; + + case 'b': // bss section + SecFlags |= Alloc; + if (SecFlags & InitData) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~Load; + break; + + case 'd': // data section + SecFlags |= InitData; + if (SecFlags & Alloc) + return TokError("conflicting section flags 'b' and 'd'."); + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'n': // section is not loaded + SecFlags |= NoLoad; + SecFlags &= ~Load; + break; + + case 'r': // read-only + ReadOnlyRemoved = false; + SecFlags |= NoWrite; + if ((SecFlags & Code) == 0) + SecFlags |= InitData; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 's': // shared section + SecFlags |= Shared | InitData; + SecFlags &= ~NoWrite; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + break; + + case 'w': // writable + SecFlags &= ~NoWrite; + ReadOnlyRemoved = true; + break; + + case 'x': // executable section + SecFlags |= Code; + if ((SecFlags & NoLoad) == 0) + SecFlags |= Load; + if (!ReadOnlyRemoved) + SecFlags |= NoWrite; + break; + + case 'y': // not readable + SecFlags |= NoRead | NoWrite; + break; + + default: + return TokError("unknown flag"); + } + } + + *Flags = 0; + + if (SecFlags == None) + SecFlags = InitData; + + if (SecFlags & Code) + *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE; + if (SecFlags & InitData) + *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; + if ((SecFlags & Alloc) && (SecFlags & Load) == 0) + *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + if (SecFlags & NoLoad) + *Flags |= COFF::IMAGE_SCN_LNK_REMOVE; + if ((SecFlags & NoRead) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_READ; + if ((SecFlags & NoWrite) == 0) + *Flags |= COFF::IMAGE_SCN_MEM_WRITE; + if (SecFlags & Shared) + *Flags |= COFF::IMAGE_SCN_MEM_SHARED; + + return false; +} + /// ParseDirectiveSymbolAttribute /// ::= { ".weak", ... } [ identifier ( , identifier )* ] bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { @@ -174,6 +292,60 @@ bool COFFAsmParser::ParseSectionSwitch(StringRef Section, return false; } +bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { + if (!getLexer().is(AsmToken::Identifier)) + return true; + + SectionName = getTok().getIdentifier(); + Lex(); + return false; +} + +// .section name [, "flags"] +// +// Supported flags: +// a: Ignored. +// b: BSS section (uninitialized data) +// d: data section (initialized data) +// n: Discardable section +// r: Readable section +// s: Shared section +// w: Writable section +// x: Executable section +// y: Not-readable section (clears 'r') +// +// Subsections are not supported. +bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + if (ParseSectionFlags(FlagsStr, &Flags)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + SectionKind Kind = computeSectionKind(Flags); + ParseSectionSwitch(SectionName, Flags, Kind); + return false; +} + bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { StringRef SymbolName; diff --git a/test/MC/COFF/section-invalid-flags.s b/test/MC/COFF/section-invalid-flags.s new file mode 100644 index 00000000000..17b1550a904 --- /dev/null +++ b/test/MC/COFF/section-invalid-flags.s @@ -0,0 +1,8 @@ +// RUN: not llvm-mc -triple i386-pc-win32 -filetype=obj %s 2>&1 | FileCheck %s +// RUN: not llvm-mc -triple x86_64-pc-win32 -filetype=obj %s 2>&1 | FileCheck %s + +// CHECK: error: conflicting section flags 'b' and 'd' +.section s_db,"db"; .long 1 + +// CHECK: error: conflicting section flags 'b' and 'd' +.section s_bd,"bd"; .long 1 diff --git a/test/MC/COFF/section.s b/test/MC/COFF/section.s new file mode 100644 index 00000000000..d7547e626eb --- /dev/null +++ b/test/MC/COFF/section.s @@ -0,0 +1,170 @@ +// RUN: llvm-mc -triple i386-pc-win32 -filetype=obj %s | llvm-readobj -s | FileCheck %s +// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-readobj -s | FileCheck %s + +.section .foo$bar; .long 1 +.section .foo@bar; .long 1 +.section ABCDEFGHIJKLMNOPQRSTUVWXYZ; .long 1 +.section abcdefghijklmnopqrstuvwxyz; .long 1 +.section _0123456789; .long 1 + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Name: .foo$bar +// CHECK: } +// CHECK: Section { +// CHECK: Name: .foo@bar +// CHECK: } +// CHECK: Section { +// CHECK: Name: ABCDEFGHIJKLMNOPQRSTUVWXYZ +// CHECK: } +// CHECK: Section { +// CHECK: Name: abcdefghijklmnopqrstuvwxyz +// CHECK: } +// CHECK: Section { +// CHECK: Name: _0123456789 +// CHECK: } + +// Test that the defaults are used +.section s ; .long 1 +.section s_, "" ; .long 1 +.section s_a,"a"; .long 1 +.section s_b,"b"; .long 1 +.section s_d,"d"; .long 1 +.section s_n,"n"; .long 1 +.section s_r,"r"; .long 1 +.section s_s,"s"; .long 1 +.section s_w,"w"; .long 1 +.section s_x,"x"; .long 1 +.section s_y,"y"; .long 1 + +// CHECK: Section { +// CHECK: Name: s +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_ +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_a +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_b +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_UNINITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_d +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_n +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_LNK_REMOVE +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_r +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_s +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_SHARED +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_w +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_x +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_CODE +// CHECK-NEXT: IMAGE_SCN_MEM_EXECUTE +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: } +// CHECK: Section { +// CHECK: Name: s_y +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: ] +// CHECK: } + +// w makes read-only to readable +.section s_rw,"rw"; .long 1 +// CHECK: Section { +// CHECK: Name: s_rw +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: IMAGE_SCN_MEM_WRITE +// CHECK-NEXT: ] +// CHECK: } + +// r cancels w +.section s_wr,"wr"; .long 1 +// CHECK: Section { +// CHECK: Name: s_wr +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: IMAGE_SCN_MEM_READ +// CHECK-NEXT: ] +// CHECK: } + +// y cancels both +.section s_rwy,"rwy"; .long 1 +// CHECK: Section { +// CHECK: Name: s_rwy +// CHECK: Characteristics [ +// CHECK-NEXT: IMAGE_SCN_ALIGN_1BYTES +// CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +// CHECK-NEXT: ] +// CHECK: } + +// CHECK: ] diff --git a/test/MC/COFF/seh-section.s b/test/MC/COFF/seh-section.s index 7f05cc372e0..026c0d73348 100644 --- a/test/MC/COFF/seh-section.s +++ b/test/MC/COFF/seh-section.s @@ -1,7 +1,6 @@ // This test ensures that, if the section containing a function has a suffix // (e.g. .text$foo), its unwind info section also has a suffix (.xdata$foo). // RUN: llvm-mc -filetype=obj -triple x86_64-pc-win32 %s | llvm-readobj -s -sd | FileCheck %s -// XFAIL: * // CHECK: Name: .xdata$foo // CHECK-NEXT: VirtualSize @@ -16,7 +15,6 @@ // CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES // CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA // CHECK-NEXT: IMAGE_SCN_MEM_READ -// CHECK-NEXT: IMAGE_SCN_MEM_WRITE // CHECK-NEXT: ] // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 01050200 05500402