diff options
-rw-r--r-- | docs/Extensions.rst | 38 | ||||
-rw-r--r-- | include/llvm/MC/MCContext.h | 8 | ||||
-rw-r--r-- | include/llvm/MC/MCSectionCOFF.h | 14 | ||||
-rw-r--r-- | lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 3 | ||||
-rw-r--r-- | lib/MC/MCContext.cpp | 44 | ||||
-rw-r--r-- | lib/MC/MCParser/COFFAsmParser.cpp | 106 | ||||
-rw-r--r-- | lib/MC/WinCOFFStreamer.cpp | 3 | ||||
-rw-r--r-- | test/MC/COFF/section-comdat.s | 188 |
8 files changed, 355 insertions, 49 deletions
diff --git a/docs/Extensions.rst b/docs/Extensions.rst index 925d727..e308dbc 100644 --- a/docs/Extensions.rst +++ b/docs/Extensions.rst @@ -105,3 +105,41 @@ Supported COMDAT types: .section .xdata$foo .linkonce associative .text$foo ... + +``.section`` Directive +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +MC supports passing the information in ``.linkonce`` at the end of +``.section``. For example, these two codes are equivalent + +.. code-block:: gas + + .section secName, "dr", discard, "Symbol1" + .globl Symbol1 + Symbol1: + .long 1 + +.. code-block:: gas + + .section secName, "dr" + .linkonce discard + .globl Symbol1 + Symbol1: + .long 1 + +Note that in the combined form the COMDAT symbol is explict. This +extension exits to support multiple sections with the same name in +different comdats: + + +.. code-block:: gas + + .section secName, "dr", discard, "Symbol1" + .globl Symbol1 + Symbol1: + .long 1 + + .section secName, "dr", discard, "Symbol2" + .globl Symbol2 + Symbol2: + .long 1 diff --git a/include/llvm/MC/MCContext.h b/include/llvm/MC/MCContext.h index 8fba18c..c8b6626 100644 --- a/include/llvm/MC/MCContext.h +++ b/include/llvm/MC/MCContext.h @@ -258,9 +258,15 @@ namespace llvm { const MCSectionCOFF *getCOFFSection(StringRef Section, unsigned Characteristics, - SectionKind Kind, int Selection = 0, + SectionKind Kind, + StringRef COMDATSymName, + int Selection, const MCSectionCOFF *Assoc = 0); + const MCSectionCOFF *getCOFFSection(StringRef Section, + unsigned Characteristics, + SectionKind Kind); + const MCSectionCOFF *getCOFFSection(StringRef Section); /// @} diff --git a/include/llvm/MC/MCSectionCOFF.h b/include/llvm/MC/MCSectionCOFF.h index 754e829..45c84ae 100644 --- a/include/llvm/MC/MCSectionCOFF.h +++ b/include/llvm/MC/MCSectionCOFF.h @@ -19,6 +19,7 @@ #include "llvm/Support/COFF.h" namespace llvm { +class MCSymbol; /// MCSectionCOFF - This represents a section on Windows class MCSectionCOFF : public MCSection { @@ -32,6 +33,11 @@ namespace llvm { /// drawn from the enums below. mutable unsigned Characteristics; + /// The COMDAT symbol of this section. Only valid if this is a COMDAT + /// section. Two COMDAT sections are merged if they have the same + /// COMDAT symbol. + const MCSymbol *COMDATSymbol; + /// Selection - This is the Selection field for the section symbol, if /// it is a COMDAT section (Characteristics & IMAGE_SCN_LNK_COMDAT) != 0 mutable int Selection; @@ -44,9 +50,11 @@ namespace llvm { private: friend class MCContext; MCSectionCOFF(StringRef Section, unsigned Characteristics, - int Selection, const MCSectionCOFF *Assoc, SectionKind K) - : MCSection(SV_COFF, K), SectionName(Section), - Characteristics(Characteristics), Selection(Selection), Assoc(Assoc) { + const MCSymbol *COMDATSymbol, int Selection, + const MCSectionCOFF *Assoc, SectionKind K) + : MCSection(SV_COFF, K), SectionName(Section), + Characteristics(Characteristics), COMDATSymbol(COMDATSymbol), + Selection(Selection), Assoc(Assoc) { assert ((Characteristics & 0x00F00000) == 0 && "alignment must not be set upon section creation"); assert ((Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) == diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 66ba3ec..59d7b57 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -733,6 +733,7 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, return getContext().getCOFFSection(Name, Characteristics, Kind, + "", Selection); } @@ -768,7 +769,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; return getContext().getCOFFSection(Name.str(), Characteristics, - Kind, COFF::IMAGE_COMDAT_SELECT_ANY); + Kind, "", COFF::IMAGE_COMDAT_SELECT_ANY); } if (Kind.isText()) diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 67904f6..3b45d16 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -34,8 +34,7 @@ typedef std::pair<std::string, std::string> SectionGroupPair; typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy; typedef std::map<SectionGroupPair, const MCSectionELF *> ELFUniqueMapTy; -typedef StringMap<const MCSectionCOFF*> COFFUniqueMapTy; - +typedef std::map<SectionGroupPair, const MCSectionCOFF *> COFFUniqueMapTy; MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, const MCObjectFileInfo *mofi, const SourceMgr *mgr, @@ -280,32 +279,51 @@ const MCSectionELF *MCContext::CreateELFGroupSection() { return Result; } -const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section, - unsigned Characteristics, - SectionKind Kind, int Selection, - const MCSectionCOFF *Assoc) { +const MCSectionCOFF * +MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, + SectionKind Kind, StringRef COMDATSymName, + int Selection, const MCSectionCOFF *Assoc) { if (COFFUniquingMap == 0) COFFUniquingMap = new COFFUniqueMapTy(); COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; // Do the lookup, if we have a hit, return it. - StringMapEntry<const MCSectionCOFF*> &Entry = Map.GetOrCreateValue(Section); - if (Entry.getValue()) return Entry.getValue(); - MCSectionCOFF *Result = new (*this) MCSectionCOFF(Entry.getKey(), - Characteristics, - Selection, Assoc, Kind); + SectionGroupPair P(Section, COMDATSymName); + std::pair<COFFUniqueMapTy::iterator, bool> Entry = + Map.insert(std::make_pair(P, (MCSectionCOFF *)0)); + COFFUniqueMapTy::iterator Iter = Entry.first; + if (!Entry.second) + return Iter->second; + + const MCSymbol *COMDATSymbol = NULL; + if (!COMDATSymName.empty()) + COMDATSymbol = GetOrCreateSymbol(COMDATSymName); + + MCSectionCOFF *Result = + new (*this) MCSectionCOFF(Iter->first.first, Characteristics, + COMDATSymbol, Selection, Assoc, Kind); - Entry.setValue(Result); + Iter->second = Result; return Result; } +const MCSectionCOFF * +MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, + SectionKind Kind) { + return getCOFFSection(Section, Characteristics, Kind, "", 0); +} + const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section) { if (COFFUniquingMap == 0) COFFUniquingMap = new COFFUniqueMapTy(); COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; - return Map.lookup(Section); + SectionGroupPair P(Section, ""); + COFFUniqueMapTy::iterator Iter = Map.find(P); + if (Iter == Map.end()) + return 0; + return Iter->second; } //===----------------------------------------------------------------------===// diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp index df1794c..d8343a3 100644 --- a/lib/MC/MCParser/COFFAsmParser.cpp +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -35,6 +35,10 @@ class COFFAsmParser : public MCAsmParserExtension { unsigned Characteristics, SectionKind Kind); + bool ParseSectionSwitch(StringRef Section, unsigned Characteristics, + SectionKind Kind, StringRef COMDATSymName, + COFF::COMDATType Type, const MCSectionCOFF *Assoc); + bool ParseSectionName(StringRef &SectionName); bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags); @@ -111,6 +115,8 @@ class COFFAsmParser : public MCAsmParserExtension { bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveEndef(StringRef, SMLoc); bool ParseDirectiveSecRel32(StringRef, SMLoc); + bool parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc); bool ParseDirectiveLinkOnce(StringRef, SMLoc); // Win64 EH directives. @@ -284,12 +290,22 @@ bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) { bool COFFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Characteristics, SectionKind Kind) { + return ParseSectionSwitch(Section, Characteristics, Kind, "", + COFF::IMAGE_COMDAT_SELECT_ANY, 0); +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind, + StringRef COMDATSymName, + COFF::COMDATType Type, + const MCSectionCOFF *Assoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in section switching directive"); Lex(); getStreamer().SwitchSection(getContext().getCOFFSection( - Section, Characteristics, Kind)); + Section, Characteristics, Kind, COMDATSymName, Type, Assoc)); return false; } @@ -303,7 +319,7 @@ bool COFFAsmParser::ParseSectionName(StringRef &SectionName) { return false; } -// .section name [, "flags"] +// .section name [, "flags"] [, identifier [ identifier ], identifier] // // Supported flags: // a: Ignored. @@ -340,11 +356,30 @@ bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { return true; } + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + StringRef COMDATSymName; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + Flags |= COFF::IMAGE_SCN_LNK_COMDAT; + + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected comma in directive"); + Lex(); + + if (getParser().parseIdentifier(COMDATSymName)) + return TokError("expected identifier in directive"); + } + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); SectionKind Kind = computeSectionKind(Flags); - ParseSectionSwitch(SectionName, Flags, Kind); + ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc); return false; } @@ -409,37 +444,29 @@ bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) { return false; } -/// ParseDirectiveLinkOnce -/// ::= .linkonce [ identifier [ identifier ] ] -bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { - COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; - - if (getLexer().is(AsmToken::Identifier)) { - StringRef TypeId = getTok().getIdentifier(); +/// ::= [ identifier [ identifier ] ] +bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc) { + StringRef TypeId = getTok().getIdentifier(); - Type = StringSwitch<COFF::COMDATType>(TypeId) - .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) - .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) - .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) - .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) - .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) - .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) - .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) - .Default((COFF::COMDATType)0); + Type = StringSwitch<COFF::COMDATType>(TypeId) + .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES) + .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY) + .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE) + .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH) + .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST) + .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST) + .Default((COFF::COMDATType)0); - if (Type == 0) - return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); + if (Type == 0) + return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'")); - Lex(); - } - - const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( - getStreamer().getCurrentSection().first); + Lex(); - const MCSectionCOFF *Assoc = 0; if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { - StringRef AssocName; SMLoc Loc = getTok().getLoc(); + StringRef AssocName; if (ParseSectionName(AssocName)) return TokError("expected associated section name"); @@ -447,14 +474,33 @@ bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { getContext().getCOFFSection(AssocName)); if (!Assoc) return Error(Loc, "cannot associate unknown section '" + AssocName + "'"); - if (Assoc == Current) - return Error(Loc, "cannot associate a section with itself"); if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)) return Error(Loc, "associated section must be a COMDAT section"); if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) return Error(Loc, "associated section cannot be itself associative"); } + return false; +} + +/// ParseDirectiveLinkOnce +/// ::= .linkonce [ identifier [ identifier ] ] +bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + if (getLexer().is(AsmToken::Identifier)) + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + return true; + + const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( + getStreamer().getCurrentSection().first); + + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + if (Assoc == Current) + return Error(Loc, "cannot associate a section with itself"); + } + if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) return Error(Loc, Twine("section '") + Current->getSectionName() + "' is already linkonce"); diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index 6744df5..7fc114c 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -151,7 +151,8 @@ void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, int Selection = COFF::IMAGE_COMDAT_SELECT_LARGEST; const MCSection *Section = MCStreamer::getContext().getCOFFSection( - SectionName, Characteristics, SectionKind::getBSS(), Selection); + SectionName, Characteristics, SectionKind::getBSS(), Symbol->getName(), + Selection); MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section); diff --git a/test/MC/COFF/section-comdat.s b/test/MC/COFF/section-comdat.s new file mode 100644 index 0000000..dd5be87 --- /dev/null +++ b/test/MC/COFF/section-comdat.s @@ -0,0 +1,188 @@ +// RUN: llvm-mc -triple i386-pc-win32 -filetype=obj %s | llvm-readobj -s -t | FileCheck %s +// RUN: llvm-mc -triple x86_64-pc-win32 -filetype=obj %s | llvm-readobj -s -t | FileCheck %s + +.section assocSec +.linkonce +.long 1 + +.section secName, "dr", discard, "Symbol1" +.globl Symbol1 +Symbol1: +.long 1 + +.section secName, "dr", one_only, "Symbol2" +.globl Symbol2 +Symbol2: +.long 1 + +.section SecName, "dr", same_size, "Symbol3" +.globl Symbol3 +Symbol3: +.long 1 + +.section SecName, "dr", same_contents, "Symbol4" +.globl Symbol4 +Symbol4: +.long 1 + +.section SecName, "dr", associative assocSec, "Symbol5" +.globl Symbol5 +Symbol5: +.long 1 + +.section SecName, "dr", largest, "Symbol6" +.globl Symbol6 +Symbol6: +.long 1 + +.section SecName, "dr", newest, "Symbol7" +.globl Symbol7 +Symbol7: +.long 1 + +// CHECK: Sections [ +// CHECK: Section { +// CHECK: Number: 1 +// CHECK: Name: assocSec +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 2 +// CHECK: Name: secName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 3 +// CHECK: Name: secName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 4 +// CHECK: Name: SecName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 5 +// CHECK: Name: SecName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 6 +// CHECK: Name: SecName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 7 +// CHECK: Name: SecName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: Section { +// CHECK: Number: 8 +// CHECK: Name: SecName +// CHECK: Characteristics [ +// CHECK: IMAGE_SCN_LNK_COMDAT +// CHECK: ] +// CHECK: } +// CHECK: ] +// CHECK: Symbols [ +// CHECK: Symbol { +// CHECK: Name: assocSec +// CHECK: Section: assocSec (1) +// CHECK: AuxSectionDef { +// CHECK: Selection: Any +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: secName +// CHECK: Section: secName (2) +// CHECK: AuxSectionDef { +// CHECK: Selection: Any +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: secName +// CHECK: Section: secName (3) +// CHECK: AuxSectionDef { +// CHECK: Selection: NoDuplicates +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: SecName +// CHECK: Section: SecName (4) +// CHECK: AuxSectionDef { +// CHECK: Selection: SameSize +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: SecName +// CHECK: Section: SecName (5) +// CHECK: AuxSymbolCount: 1 +// CHECK: AuxSectionDef { +// CHECK: Selection: ExactMatch +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: SecName +// CHECK: Section: SecName (6) +// CHECK: AuxSectionDef { +// CHECK: Selection: Associative +// CHECK: AssocSection: assocSec (1) +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: SecName +// CHECK: Section: SecName (7) +// CHECK: AuxSectionDef { +// CHECK: Selection: Largest +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: SecName +// CHECK: Section: SecName (8) +// CHECK: AuxSectionDef { +// CHECK: Selection: Newest (0x7) +// CHECK: } +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol1 +// CHECK: Section: secName (2) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol2 +// CHECK: Section: secName (3) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol3 +// CHECK: Section: SecName (4) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol4 +// CHECK: Section: SecName (5) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol5 +// CHECK: Section: SecName (6) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol6 +// CHECK: Section: SecName (7) +// CHECK: } +// CHECK: Symbol { +// CHECK: Name: Symbol7 +// CHECK: Section: SecName (8) +// CHECK: } +// CHECK: ] |