summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp6
-rw-r--r--llvm/lib/MC/MCContext.cpp18
-rw-r--r--llvm/lib/MC/MCParser/COFFAsmParser.cpp60
-rw-r--r--llvm/lib/MC/MCSectionCOFF.cpp24
-rw-r--r--llvm/lib/MC/WinCOFFObjectWriter.cpp31
-rw-r--r--llvm/lib/MC/WinCOFFStreamer.cpp2
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);
OpenPOWER on IntegriCloud