diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 6 | ||||
-rw-r--r-- | llvm/lib/MC/MCContext.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/MC/MCParser/COFFAsmParser.cpp | 60 | ||||
-rw-r--r-- | llvm/lib/MC/MCSectionCOFF.cpp | 24 | ||||
-rw-r--r-- | llvm/lib/MC/WinCOFFObjectWriter.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/MC/WinCOFFStreamer.cpp | 2 |
6 files changed, 126 insertions, 15 deletions
diff --git a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 7e7359a8fee..3e1afc01e06 100644 --- a/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -732,8 +732,8 @@ getExplicitSectionGlobal(const GlobalValue *GV, SectionKind Kind, } return getContext().getCOFFSection(Name, Characteristics, - Selection, - Kind); + Kind, + Selection); } static const char *getCOFFSectionPrefixForUniqueGlobal(SectionKind Kind) { @@ -769,7 +769,7 @@ SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind, Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; return getContext().getCOFFSection(Name.str(), Characteristics, - COFF::IMAGE_COMDAT_SELECT_ANY, Kind); + Kind, COFF::IMAGE_COMDAT_SELECT_ANY); } if (Kind.isText()) diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index d5788332d5d..6e4d82b6e76 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -274,10 +274,10 @@ const MCSectionELF *MCContext::CreateELFGroupSection() { return Result; } -const MCSection *MCContext::getCOFFSection(StringRef Section, - unsigned Characteristics, - int Selection, - SectionKind Kind) { +const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section, + unsigned Characteristics, + SectionKind Kind, int Selection, + const MCSectionCOFF *Assoc) { if (COFFUniquingMap == 0) COFFUniquingMap = new COFFUniqueMapTy(); COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; @@ -288,12 +288,20 @@ const MCSection *MCContext::getCOFFSection(StringRef Section, MCSectionCOFF *Result = new (*this) MCSectionCOFF(Entry.getKey(), Characteristics, - Selection, Kind); + Selection, Assoc, Kind); Entry.setValue(Result); return Result; } +const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section) { + if (COFFUniquingMap == 0) + COFFUniquingMap = new COFFUniqueMapTy(); + COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; + + return Map.lookup(Section); +} + //===----------------------------------------------------------------------===// // Dwarf Management //===----------------------------------------------------------------------===// diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp index c2a22619db2..df1794c9799 100644 --- a/llvm/lib/MC/MCParser/COFFAsmParser.cpp +++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -51,6 +51,7 @@ class COFFAsmParser : public MCAsmParserExtension { addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce"); // Win64 EH directives. addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>( @@ -110,6 +111,7 @@ class COFFAsmParser : public MCAsmParserExtension { bool ParseDirectiveType(StringRef, SMLoc); bool ParseDirectiveEndef(StringRef, SMLoc); bool ParseDirectiveSecRel32(StringRef, SMLoc); + bool ParseDirectiveLinkOnce(StringRef, SMLoc); // Win64 EH directives. bool ParseSEHDirectiveStartProc(StringRef, SMLoc); @@ -407,6 +409,64 @@ 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(); + + 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 + "'")); + + Lex(); + } + + const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( + getStreamer().getCurrentSection().first); + + const MCSectionCOFF *Assoc = 0; + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + StringRef AssocName; + SMLoc Loc = getTok().getLoc(); + if (ParseSectionName(AssocName)) + return TokError("expected associated section name"); + + Assoc = static_cast<const MCSectionCOFF*>( + 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"); + } + + if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) + return Error(Loc, Twine("section '") + Current->getSectionName() + + "' is already linkonce"); + + Current->setSelection(Type, Assoc); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + return false; +} + bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { StringRef SymbolID; if (getParser().parseIdentifier(SymbolID)) diff --git a/llvm/lib/MC/MCSectionCOFF.cpp b/llvm/lib/MC/MCSectionCOFF.cpp index 6cedf0655cf..64aa2c5c49e 100644 --- a/llvm/lib/MC/MCSectionCOFF.cpp +++ b/llvm/lib/MC/MCSectionCOFF.cpp @@ -28,6 +28,17 @@ bool MCSectionCOFF::ShouldOmitSectionDirective(StringRef Name, return false; } +void MCSectionCOFF::setSelection(int Selection, + const MCSectionCOFF *Assoc) const { + assert(Selection != 0 && "invalid COMDAT selection type"); + assert((Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) == + (Assoc != 0) && + "associative COMDAT section must have an associated section"); + this->Selection = Selection; + this->Assoc = Assoc; + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; +} + void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS, const MCExpr *Subsection) const { @@ -63,12 +74,15 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: OS << "\t.linkonce same_contents\n"; break; - //NOTE: as of binutils 2.20, there is no way to specifiy select largest - // with the .linkonce directive. For now, we treat it as an invalid - // comdat selection value. + case COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE: + OS << "\t.linkonce associative " << Assoc->getSectionName() << "\n"; + break; case COFF::IMAGE_COMDAT_SELECT_LARGEST: - // OS << "\t.linkonce largest\n"; - // break; + OS << "\t.linkonce largest\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_NEWEST: + OS << "\t.linkonce newest\n"; + break; default: assert (0 && "unsupported COFF selection type"); break; diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp index 518b59ee244..cf733960881 100644 --- a/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" @@ -707,10 +708,13 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, // Assign symbol and section indexes and offsets. Header.NumberOfSections = 0; + DenseMap<COFFSection *, uint16_t> SectionIndices; for (sections::iterator i = Sections.begin(), e = Sections.end(); i != e; i++) { if (Layout.getSectionAddressSize((*i)->MCData) > 0) { - MakeSectionReal(**i, ++Header.NumberOfSections); + size_t Number = ++Header.NumberOfSections; + SectionIndices[*i] = Number; + MakeSectionReal(**i, Number); } else { (*i)->Number = -1; } @@ -754,6 +758,31 @@ void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, } } + // Fixup associative COMDAT sections. + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if ((*i)->Symbol->Aux[0].Aux.SectionDefinition.Selection != + COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + continue; + + const MCSectionCOFF &MCSec = static_cast<const MCSectionCOFF &>( + (*i)->MCData->getSection()); + + COFFSection *Assoc = SectionMap.lookup(MCSec.getAssocSection()); + if (!Assoc) { + report_fatal_error(Twine("Missing associated COMDAT section ") + + MCSec.getAssocSection()->getSectionName() + + " for section " + MCSec.getSectionName()); + } + + // Skip this section if the associated section is unused. + if (Assoc->Number == -1) + continue; + + (*i)->Symbol->Aux[0].Aux.SectionDefinition.Number = SectionIndices[Assoc]; + } + + // Assign file offsets to COFF object file structures. unsigned offset = 0; diff --git a/llvm/lib/MC/WinCOFFStreamer.cpp b/llvm/lib/MC/WinCOFFStreamer.cpp index 75f343c421b..04bfeb4c2ba 100644 --- a/llvm/lib/MC/WinCOFFStreamer.cpp +++ b/llvm/lib/MC/WinCOFFStreamer.cpp @@ -155,7 +155,7 @@ void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, int Selection = COFF::IMAGE_COMDAT_SELECT_LARGEST; const MCSection *Section = MCStreamer::getContext().getCOFFSection( - SectionName, Characteristics, Selection, SectionKind::getBSS()); + SectionName, Characteristics, SectionKind::getBSS(), Selection); MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section); |