diff --git a/llvm/include/llvm/BinaryFormat/GoObj.h b/llvm/include/llvm/BinaryFormat/GoObj.h index c4901df392b57..c68296dea3703 100644 --- a/llvm/include/llvm/BinaryFormat/GoObj.h +++ b/llvm/include/llvm/BinaryFormat/GoObj.h @@ -206,6 +206,10 @@ enum RelocType : uint16_t { R_ARM64_LDST32 = 43, R_ARM64_LDST64 = 44, R_ARM64_LDST128 = 45, + + R_WEAK = 1u << 15, + R_WEAKADDR = R_WEAK | R_ADDR, + R_WEAKADDROFF = R_WEAK | R_ADDROFF, }; } // end namespace GoObj diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h index 599124ff5d58e..8490b77e833fd 100644 --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -105,6 +105,17 @@ class MCContext { int32_t Value; }; + struct GoObjRelocOverride { + uint32_t Offset; + uint16_t Type; + }; + + struct GoObjMarkerReloc { + const MCSymbol *Target = nullptr; + uint16_t Type = 0; + int64_t Addend = 0; + }; + private: Environment Env; @@ -175,6 +186,30 @@ class MCContext { /// Go object symbol flags keyed by MC symbol. DenseMap> GoObjSymbolFlags; + /// Go object data-relocation type overrides keyed by MC symbol. LLVM IR + /// constants describe an address but not Go's weak-address variants. + DenseMap> + GoObjRelocOverrides; + + /// Go object data relocations whose inferred relocation kind is weak. + DenseMap> GoObjWeakRelocs; + + /// Go object zero-width R_KEEP targets keyed by their source symbol. + DenseMap> GoObjKeepTargets; + + /// Go object zero-width linker marker relocations keyed by source function. + DenseMap> + GoObjMarkerRelocs; + + /// Explicit LLVM global alignments for Go object data symbols. + DenseMap GoObjSymbolAlignments; + + /// Exact LLVM global sizes for Go object data symbols. + DenseMap GoObjSymbolSizes; + + /// Go type auxiliary targets for data symbols. + DenseMap GoObjGotypeTargets; + /// Go object pcsp entries keyed by MC symbol. DenseMap> GoObjSymbolPCSPEntries; @@ -596,6 +631,92 @@ class MCContext { return It->second; } + void setGoObjRelocOverrides(const MCSymbol *Sym, + std::vector Overrides) { + GoObjRelocOverrides[Sym] = std::move(Overrides); + } + + const std::vector * + getGoObjRelocOverrides(const MCSymbol *Sym) const { + auto It = GoObjRelocOverrides.find(Sym); + if (It == GoObjRelocOverrides.end()) + return nullptr; + return &It->second; + } + + void setGoObjWeakRelocs(const MCSymbol *Sym, + std::vector Offsets) { + GoObjWeakRelocs[Sym] = std::move(Offsets); + } + + const std::vector * + getGoObjWeakRelocs(const MCSymbol *Sym) const { + auto It = GoObjWeakRelocs.find(Sym); + if (It == GoObjWeakRelocs.end()) + return nullptr; + return &It->second; + } + + void setGoObjKeepTargets(const MCSymbol *Sym, + std::vector Targets) { + GoObjKeepTargets[Sym] = std::move(Targets); + } + + const std::vector * + getGoObjKeepTargets(const MCSymbol *Sym) const { + auto It = GoObjKeepTargets.find(Sym); + if (It == GoObjKeepTargets.end()) + return nullptr; + return &It->second; + } + + void setGoObjMarkerRelocs(const MCSymbol *Sym, + std::vector Relocs) { + GoObjMarkerRelocs[Sym] = std::move(Relocs); + } + + const std::vector * + getGoObjMarkerRelocs(const MCSymbol *Sym) const { + auto It = GoObjMarkerRelocs.find(Sym); + if (It == GoObjMarkerRelocs.end()) + return nullptr; + return &It->second; + } + + void setGoObjSymbolAlignment(const MCSymbol *Sym, uint32_t Alignment) { + GoObjSymbolAlignments[Sym] = Alignment; + } + + std::optional + getGoObjSymbolAlignment(const MCSymbol *Sym) const { + auto It = GoObjSymbolAlignments.find(Sym); + if (It == GoObjSymbolAlignments.end()) + return std::nullopt; + return It->second; + } + + void setGoObjSymbolSize(const MCSymbol *Sym, uint64_t Size) { + GoObjSymbolSizes[Sym] = Size; + } + + std::optional getGoObjSymbolSize(const MCSymbol *Sym) const { + auto It = GoObjSymbolSizes.find(Sym); + if (It == GoObjSymbolSizes.end()) + return std::nullopt; + return It->second; + } + + void setGoObjGotypeTarget(const MCSymbol *Sym, const MCSymbol *Target) { + GoObjGotypeTargets[Sym] = Target; + } + + const MCSymbol *getGoObjGotypeTarget(const MCSymbol *Sym) const { + auto It = GoObjGotypeTargets.find(Sym); + if (It == GoObjGotypeTargets.end()) + return nullptr; + return It->second; + } + void setGoObjSymbolPCSPEntries(const MCSymbol *Sym, std::vector Entries) { GoObjSymbolPCSPEntries[Sym] = std::move(Entries); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 7a5b10d71c815..deec928033658 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" @@ -581,6 +582,8 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { AU.addUsedIfAvailable(); } +static void collectGoObjModuleMetadata(AsmPrinter &AP, const Module &M); + bool AsmPrinter::doInitialization(Module &M) { MMI = GetMMI(); HasSplitStack = false; @@ -596,6 +599,7 @@ bool AsmPrinter::doInitialization(Module &M) { TM.getObjFileLowering()->getModuleMetadata(M); if (Target.isOSBinFormatGoObj()) { + collectGoObjModuleMetadata(*this, M); for (const Function &F : M) { if (!F.isDeclaration()) continue; @@ -855,22 +859,170 @@ MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { } static std::optional> -getGoObjSymbolFlagsMetadata(const GlobalObject *GO) { - const MDNode *MD = GO->getMetadata("goobj.symbol.flags"); +getGoObjSymbolFlags(const GlobalVariable *GV) { + uint8_t Flag = 0; + uint8_t Flag2 = 0; + + if (GV->hasLocalLinkage()) + Flag |= GoObj::SymFlagLocal; + else if (GV->isWeakForLinker()) + Flag |= GoObj::SymFlagDupok; + + if (const auto *ST = dyn_cast(GV->getValueType()); + ST && ST->hasName()) { + if (ST->getName().starts_with("go.descriptor.")) + Flag |= GoObj::SymFlagGoType; + if (ST->getName().starts_with("go.itab.")) + Flag2 |= GoObj::SymFlagItab; + } + + if (const MDNode *MD = GV->getMetadata("goobj.symbol.flags")) { + if (MD->getNumOperands() != 2) + report_fatal_error("expected !goobj.symbol.flags to have two operands"); + + auto ReadFlag = [&](unsigned I) -> uint8_t { + const auto *CI = mdconst::dyn_extract(MD->getOperand(I)); + if (!CI || CI->getValue().ugt(UINT8_MAX)) + report_fatal_error("expected !goobj.symbol.flags operands to be i8"); + return static_cast(CI->getZExtValue()); + }; + + Flag |= ReadFlag(0); + Flag2 |= ReadFlag(1); + } + + if (Flag == 0 && Flag2 == 0) + return std::nullopt; + return std::make_pair(Flag, Flag2); +} + +static std::optional> +getGoObjRelocsMetadata(const GlobalObject *GO) { + const MDNode *MD = GO->getMetadata("goobj.relocs"); if (!MD) return std::nullopt; - if (MD->getNumOperands() != 2) - report_fatal_error("expected !goobj.symbol.flags to have two operands"); + std::vector Result; + Result.reserve(MD->getNumOperands()); + for (const MDOperand &Operand : MD->operands()) { + const auto *Entry = dyn_cast(Operand); + if (!Entry || Entry->getNumOperands() != 2) + report_fatal_error("expected !goobj.relocs entries to have two operands"); + + const auto *Offset = + mdconst::dyn_extract(Entry->getOperand(0)); + const auto *Type = mdconst::dyn_extract(Entry->getOperand(1)); + if (!Offset || !Type || Offset->getValue().ugt(UINT32_MAX) || + Type->getValue().ugt(UINT16_MAX)) + report_fatal_error("expected !goobj.relocs entries to be i32 values"); + Result.push_back({static_cast(Offset->getZExtValue()), + static_cast(Type->getZExtValue())}); + } + + llvm::sort(Result, [](const auto &LHS, const auto &RHS) { + return LHS.Offset < RHS.Offset; + }); + for (size_t I = 1; I < Result.size(); ++I) + if (Result[I - 1].Offset == Result[I].Offset) + report_fatal_error("duplicate !goobj.relocs offset"); + return Result; +} + +static std::optional> +getGoObjWeakRelocsMetadata(const GlobalObject *GO) { + const MDNode *MD = GO->getMetadata("goobj.weak_relocs"); + if (!MD) + return std::nullopt; - auto ReadFlag = [&](unsigned I) -> uint8_t { - const auto *CI = mdconst::dyn_extract(MD->getOperand(I)); - if (!CI || CI->getValue().ugt(UINT8_MAX)) - report_fatal_error("expected !goobj.symbol.flags operands to be i8"); - return static_cast(CI->getZExtValue()); - }; + std::vector Result; + Result.reserve(MD->getNumOperands()); + for (const MDOperand &Operand : MD->operands()) { + const auto *Offset = mdconst::dyn_extract(Operand); + if (!Offset || Offset->getValue().ugt(UINT32_MAX)) + report_fatal_error( + "expected !goobj.weak_relocs entries to be i32 offsets"); + Result.push_back(static_cast(Offset->getZExtValue())); + } + + llvm::sort(Result); + if (std::adjacent_find(Result.begin(), Result.end()) != Result.end()) + report_fatal_error("duplicate !goobj.weak_relocs offset"); + return Result; +} + +static const GlobalValue *getGoObjMetadataGlobal(const MDOperand &Operand, + StringRef MetadataName) { + const auto *CAM = dyn_cast_or_null(Operand.get()); + const auto *GV = CAM ? dyn_cast(CAM->getValue()) : nullptr; + if (!GV) + report_fatal_error(Twine("expected !") + MetadataName + + " symbol operands to be LLVM global references"); + return GV; +} + +static void collectGoObjModuleMetadata(AsmPrinter &AP, const Module &M) { + if (const NamedMDNode *Keep = M.getNamedMetadata("goobj.keep")) { + DenseMap> Targets; + for (const MDNode *Entry : Keep->operands()) { + if (Entry->getNumOperands() != 2) + report_fatal_error("expected !goobj.keep entries to have two operands"); + const GlobalValue *Source = + getGoObjMetadataGlobal(Entry->getOperand(0), "goobj.keep"); + const GlobalValue *Target = + getGoObjMetadataGlobal(Entry->getOperand(1), "goobj.keep"); + Targets[Source].push_back(AP.getSymbol(Target)); + } + for (auto &[Source, SourceTargets] : Targets) + AP.OutContext.setGoObjKeepTargets(AP.getSymbol(Source), + std::move(SourceTargets)); + } + + if (const NamedMDNode *Gotypes = M.getNamedMetadata("goobj.gotype")) { + DenseSet Sources; + for (const MDNode *Entry : Gotypes->operands()) { + if (Entry->getNumOperands() != 2) + report_fatal_error( + "expected !goobj.gotype entries to have two operands"); + const GlobalValue *Source = + getGoObjMetadataGlobal(Entry->getOperand(0), "goobj.gotype"); + const GlobalValue *Target = + getGoObjMetadataGlobal(Entry->getOperand(1), "goobj.gotype"); + if (!Sources.insert(Source).second) + report_fatal_error("duplicate !goobj.gotype source"); + AP.OutContext.setGoObjGotypeTarget(AP.getSymbol(Source), + AP.getSymbol(Target)); + } + } - return std::make_pair(ReadFlag(0), ReadFlag(1)); + if (const NamedMDNode *Markers = + M.getNamedMetadata("goobj.marker_relocs")) { + DenseMap> + Relocs; + for (const MDNode *Entry : Markers->operands()) { + if (Entry->getNumOperands() != 4) + report_fatal_error( + "expected !goobj.marker_relocs entries to have four operands"); + const GlobalValue *Source = + getGoObjMetadataGlobal(Entry->getOperand(0), + "goobj.marker_relocs"); + const GlobalValue *Target = + getGoObjMetadataGlobal(Entry->getOperand(1), + "goobj.marker_relocs"); + const auto *Type = + mdconst::dyn_extract(Entry->getOperand(2)); + const auto *Addend = + mdconst::dyn_extract(Entry->getOperand(3)); + if (!isa(Source) || !Type || + Type->getValue().ugt(UINT16_MAX) || !Addend) + report_fatal_error("invalid !goobj.marker_relocs entry"); + Relocs[Source].push_back( + {AP.getSymbol(Target), static_cast(Type->getZExtValue()), + Addend->getSExtValue()}); + } + for (auto &[Source, SourceRelocs] : Relocs) + AP.OutContext.setGoObjMarkerRelocs(AP.getSymbol(Source), + std::move(SourceRelocs)); + } } /// EmitGlobalVariable - Emit the specified global variable to the .s file. @@ -908,8 +1060,14 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { if (TM.getTargetTriple().isOSBinFormatGoObj()) { if (std::optional> Flags = - getGoObjSymbolFlagsMetadata(GV)) + getGoObjSymbolFlags(GV)) OutContext.setGoObjSymbolFlags(GVSym, Flags->first, Flags->second); + if (std::optional> Relocs = + getGoObjRelocsMetadata(GV)) + OutContext.setGoObjRelocOverrides(GVSym, std::move(*Relocs)); + if (std::optional> WeakRelocs = + getGoObjWeakRelocsMetadata(GV)) + OutContext.setGoObjWeakRelocs(GVSym, std::move(*WeakRelocs)); } // getOrCreateEmuTLSControlSym only creates the symbol with name and default @@ -947,6 +1105,11 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { // with a specified alignment is a prompt way to break globals emitted to // sections and expected to be contiguous (e.g. ObjC metadata). const Align Alignment = getGVAlignment(GV, DL); + if (TM.getTargetTriple().isOSBinFormatGoObj()) { + OutContext.setGoObjSymbolAlignment( + GVSym, static_cast(Alignment.value())); + OutContext.setGoObjSymbolSize(GVSym, Size); + } for (auto &Handler : Handlers) Handler->setSymbolSize(GVSym, Size); diff --git a/llvm/lib/MC/GoObjObjectWriter.cpp b/llvm/lib/MC/GoObjObjectWriter.cpp index 01559fde3bedf..f52a39d7bb931 100644 --- a/llvm/lib/MC/GoObjObjectWriter.cpp +++ b/llvm/lib/MC/GoObjObjectWriter.cpp @@ -44,6 +44,11 @@ int64_t MCGoObjObjectTargetWriter::getRelocAddend(const MCValue &Target, namespace { +struct GoObjSymRef { + uint32_t PkgIdx = GoObj::PkgIdxInvalid; + uint32_t SymIdx = 0; +}; + struct GoObjSymbol { struct Relocation { uint32_t Offset = 0; @@ -55,8 +60,14 @@ struct GoObjSymbol { }; struct Auxiliary { - uint8_t Type = 0; + Auxiliary(uint8_t Type, uint32_t TargetSymbolIndex) + : Type(Type), TargetSymbolIndex(TargetSymbolIndex) {} + Auxiliary(uint8_t Type, GoObjSymRef DirectTarget) + : Type(Type), DirectTarget(DirectTarget) {} + + uint8_t Type; uint32_t TargetSymbolIndex = 0; + std::optional DirectTarget; }; std::string Name; @@ -76,11 +87,6 @@ struct GoObjSymbol { std::vector Auxiliaries; }; -struct GoObjSymRef { - uint32_t PkgIdx = GoObj::PkgIdxInvalid; - uint32_t SymIdx = 0; -}; - struct GoObjPCTabEntry { uint64_t PC = 0; int32_t Value = 0; @@ -146,7 +152,7 @@ void addDefinedSymbol(std::vector &Symbols, const MCSymbol *MCSym, uint64_t SectionEnd, GoObj::DefinedSymbolBlock DefinedBlock, StringRef Name, uint8_t Type, uint8_t Flag, uint8_t Flag2, uint16_t ABI, - uint64_t Size, ArrayRef Data) { + uint64_t Size, uint32_t Align, ArrayRef Data) { GoObjSymbol Sym; Sym.Name = Name.str(); Sym.Symbol = MCSym; @@ -159,6 +165,7 @@ void addDefinedSymbol(std::vector &Symbols, const MCSymbol *MCSym, Sym.Flag2 = Flag2; Sym.ABI = ABI; Sym.Size = Size; + Sym.Align = Align; Sym.Data.append(Data.begin(), Data.end()); Symbols.push_back(std::move(Sym)); } @@ -508,7 +515,8 @@ uint64_t GoObjObjectWriter::writeObject() { std::vector SectionSymbols; for (const MCSymbol &Symbol : Asm->symbols()) { if (Symbol.isTemporary() || !Symbol.isInSection() || - &Symbol.getSection() != &Section) + &Symbol.getSection() != &Section || + &Symbol == Section.getBeginSymbol()) continue; uint64_t Offset = Asm->getSymbolOffset(Symbol); if (Offset > SectionSize) @@ -537,16 +545,19 @@ uint64_t GoObjObjectWriter::writeObject() { : GoObj::SymABI0; uint8_t Flag = 0; uint8_t Flag2 = 0; + uint32_t Align = 0; if (MCSym) { if (std::optional> Flags = Asm->getContext().getGoObjSymbolFlags(MCSym)) { Flag = Flags->first; Flag2 = Flags->second; } + Align = + Asm->getContext().getGoObjSymbolAlignment(MCSym).value_or(0); } addDefinedSymbol(Symbols, MCSym, &Section, Begin, End, Config.DefaultDefinedSymbolBlock, Name, Type, Flag, - Flag2, ABI, Size, Data); + Flag2, ABI, Size, Align, Data); }; if (SectionSymbols.empty()) { @@ -554,13 +565,24 @@ uint64_t GoObjObjectWriter::writeObject() { continue; } - if (SectionSymbols.front().Offset != 0) - AddSectionSymbol(nullptr, Section.getName(), 0, - SectionSymbols.front().Offset); - for (size_t I = 0, E = SectionSymbols.size(); I != E; ++I) { uint64_t Begin = SectionSymbols[I].Offset; - uint64_t End = I + 1 == E ? SectionSize : SectionSymbols[I + 1].Offset; + uint64_t End = SectionSize; + for (size_t J = I + 1; J != E; ++J) { + if (SectionSymbols[J].Offset > Begin) { + End = SectionSymbols[J].Offset; + break; + } + } + if (std::optional ExactSize = + Asm->getContext().getGoObjSymbolSize( + SectionSymbols[I].Symbol)) { + if (*ExactSize > SectionSize - Begin || + Begin + *ExactSize > End) + report_fatal_error( + "GoObj global size overlaps the next section symbol"); + End = Begin + *ExactSize; + } AddSectionSymbol(SectionSymbols[I].Symbol, SectionSymbols[I].Symbol->getName(), Begin, End); } @@ -840,12 +862,82 @@ uint64_t GoObjObjectWriter::writeObject() { else RelocType = GoObj::R_ADDROFF; } + if (Source.Symbol) { + if (const auto *Overrides = + Asm->getContext().getGoObjRelocOverrides(Source.Symbol)) { + auto It = std::lower_bound( + Overrides->begin(), Overrides->end(), + static_cast(LocalOffset), + [](const MCContext::GoObjRelocOverride &Override, uint32_t Offset) { + return Override.Offset < Offset; + }); + if (It != Overrides->end() && It->Offset == LocalOffset) + RelocType = It->Type; + } + if (const auto *WeakRelocs = + Asm->getContext().getGoObjWeakRelocs(Source.Symbol); + WeakRelocs && + std::binary_search(WeakRelocs->begin(), WeakRelocs->end(), + static_cast(LocalOffset))) + RelocType |= GoObj::R_WEAK; + } Source.Relocations.push_back({static_cast(LocalOffset), Reloc.Size, RelocType, Addend, TargetSymRef.PkgIdx, TargetSymRef.SymIdx}); } + // R_KEEP has no bytes or MC fixup. It is a Go linker reachability edge + // carried separately from normal LLVM relocations by !goobj.keep. + for (GoObjSymbol &Source : Symbols) { + if (!Source.Symbol) + continue; + const auto *Targets = Asm->getContext().getGoObjKeepTargets(Source.Symbol); + if (!Targets) + continue; + for (const MCSymbol *Target : *Targets) { + GoObjRelocationEntry Reloc; + Reloc.Symbol = Target; + int64_t Addend = 0; + GoObjSymRef TargetSymRef = GetTargetSymRef(Reloc, Addend); + Source.Relocations.push_back({0, 0, GoObj::R_KEEP, Addend, + TargetSymRef.PkgIdx, TargetSymRef.SymIdx}); + } + } + + for (GoObjSymbol &Source : Symbols) { + if (!Source.Symbol) + continue; + const auto *Markers = + Asm->getContext().getGoObjMarkerRelocs(Source.Symbol); + if (!Markers) + continue; + for (const MCContext::GoObjMarkerReloc &Marker : *Markers) { + GoObjRelocationEntry Reloc; + Reloc.Symbol = Marker.Target; + int64_t Addend = Marker.Addend; + GoObjSymRef TargetSymRef = GetTargetSymRef(Reloc, Addend); + Source.Relocations.push_back( + {0, 0, Marker.Type, Addend, TargetSymRef.PkgIdx, TargetSymRef.SymIdx}); + } + } + + for (GoObjSymbol &Source : Symbols) { + if (!Source.Symbol) + continue; + const MCSymbol *Target = + Asm->getContext().getGoObjGotypeTarget(Source.Symbol); + if (!Target) + continue; + GoObjRelocationEntry Reloc; + Reloc.Symbol = Target; + int64_t Addend = 0; + GoObjSymRef TargetSymRef = GetTargetSymRef(Reloc, Addend); + if (Addend != 0) + report_fatal_error("GoObj gotype auxiliary target has an addend"); + Source.Auxiliaries.emplace_back(GoObj::AuxGotype, TargetSymRef); + } + for (GoObjSymbol &Symbol : Symbols) { llvm::stable_sort(Symbol.Relocations, [](const GoObjSymbol::Relocation &LHS, @@ -975,9 +1067,14 @@ uint64_t GoObjObjectWriter::writeObject() { for (uint32_t Index : DefinedSymbolOrder) { const GoObjSymbol &Symbol = Symbols[Index]; for (const GoObjSymbol::Auxiliary &Aux : Symbol.Auxiliaries) { - if (Aux.TargetSymbolIndex >= DefinedSymRefs.size()) - report_fatal_error("GoObj auxiliary target symbol index is invalid"); - GoObjSymRef Ref = DefinedSymRefs[Aux.TargetSymbolIndex]; + GoObjSymRef Ref; + if (Aux.DirectTarget) { + Ref = *Aux.DirectTarget; + } else { + if (Aux.TargetSymbolIndex >= DefinedSymRefs.size()) + report_fatal_error("GoObj auxiliary target symbol index is invalid"); + Ref = DefinedSymRefs[Aux.TargetSymbolIndex]; + } W.write(Aux.Type); W.write(Ref.PkgIdx); W.write(Ref.SymIdx); diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp index 180d3ed43a893..01d07a772c963 100644 --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -170,6 +170,13 @@ void MCContext::reset() { GoObjSymbolStackSizes.clear(); GoObjSymbolArgSizes.clear(); GoObjSymbolFlags.clear(); + GoObjRelocOverrides.clear(); + GoObjWeakRelocs.clear(); + GoObjKeepTargets.clear(); + GoObjMarkerRelocs.clear(); + GoObjSymbolAlignments.clear(); + GoObjSymbolSizes.clear(); + GoObjGotypeTargets.clear(); GoObjSymbolPCSPEntries.clear(); Symbols.clear(); Allocator.Reset(); diff --git a/llvm/test/CodeGen/AArch64/goobj-data-section-symbol.ll b/llvm/test/CodeGen/AArch64/goobj-data-section-symbol.ll new file mode 100644 index 0000000000000..8cfa1f1e6aa72 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/goobj-data-section-symbol.ll @@ -0,0 +1,44 @@ +; RUN: llc -mtriple=aarch64-apple-darwin-goobj -filetype=obj < %s -o %t.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.o | FileCheck %s +; RUN: opt -passes='default' -S < %s | llc -mtriple=aarch64-apple-darwin-goobj -filetype=obj -o %t.opt.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.opt.o | FileCheck %s + +@inter = external global i8 +@type = external global i8 +@method = external global i8 +@external_gotype = external global i8 + +%go.descriptor.test = type <{ i8 }> +%go.itab.test = type <{ ptr, ptr, i32, [4 x i8], ptr }> + +@gotype = constant i8 0, section ".rodata", align 1 +@cache0 = global <{ ptr, ptr, [8 x i8] }> zeroinitializer, section ".data", align 16 +@cache1 = global <{ ptr, ptr, [8 x i8] }> zeroinitializer, section ".data", align 16 +@local = internal constant i8 0, section ".rodata", align 1 +@descriptor = weak constant %go.descriptor.test <{ i8 0 }>, section ".rodata", align 1, !goobj.symbol.flags !0 +@llvm.compiler.used = appending global [5 x ptr] [ptr @cache0, ptr @cache1, ptr @gotype, ptr @external_gotype, ptr @local], section "llvm.metadata" + +@itab = weak constant %go.itab.test <{ + ptr @inter, + ptr @type, + i32 123, + [4 x i8] zeroinitializer, + ptr @method +}>, section ".rodata", align 8, !goobj.weak_relocs !1 + +!0 = !{i32 4, i32 1} +!1 = !{i32 24} +!goobj.gotype = !{!5, !6} +!5 = !{ptr @cache0, ptr @gotype} +!6 = !{ptr @cache1, ptr @external_gotype} + +; CHECK-DAG: symdef {{[0-9]+}}: cache0 abi=0 type=7 size=24 align=16 +; CHECK-DAG: symdef {{[0-9]+}}: cache1 abi=0 type=7 size=24 align=16 +; CHECK-DAG: symdef {{[0-9]+}}: local abi=0 type=3 size=1 align=1 flag=2 flag2=0 +; CHECK-DAG: symdef {{[0-9]+}}: descriptor abi=0 type=3 size=1 align=1 flag=69 flag2=1 +; CHECK-DAG: symdef {{[0-9]+}}: itab abi=0 type=3 size=32 align=8 flag=1 flag2=2 +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=0 size=8 type=1 add=0 target=inter +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=8 size=8 type=1 add=0 target=type +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=24 size=8 type=32769 add=0 target=method +; CHECK: aux {{[0-9]+}}.{{[0-9]+}}: type=gotype target=gotype +; CHECK: aux {{[0-9]+}}.{{[0-9]+}}: type=gotype target=external_gotype diff --git a/llvm/test/CodeGen/X86/goobj-data-relocations.ll b/llvm/test/CodeGen/X86/goobj-data-relocations.ll new file mode 100644 index 0000000000000..c5fba381d84f4 --- /dev/null +++ b/llvm/test/CodeGen/X86/goobj-data-relocations.ll @@ -0,0 +1,12 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-goobj -filetype=obj < %s -o %t.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.o | FileCheck %s + +%go.descriptor.weak_offset = type <{ i32 }> + +@target = constant i8 0, section ".rodata", align 1 +@weak_offset = constant %go.descriptor.weak_offset <{ i32 ptrtoint (ptr @target to i32) }>, section ".rodata", align 4, !goobj.weak_relocs !0 + +!0 = !{i32 0} + +; CHECK: symdef {{[0-9]+}}: weak_offset abi=0 type=3 size=4 +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=0 size=4 type=32773 add=0 target=target diff --git a/llvm/test/CodeGen/X86/goobj-filetype.ll b/llvm/test/CodeGen/X86/goobj-filetype.ll index 854cece739ef8..0f0867f52eb7b 100644 --- a/llvm/test/CodeGen/X86/goobj-filetype.ll +++ b/llvm/test/CodeGen/X86/goobj-filetype.ll @@ -23,30 +23,28 @@ entry: ; LINKABLE: flags: 0 ; CHECK: file-count: 1 ; CHECK-NEXT: file 0: llvm-ir -; CHECK: symdef-count: 7 -; CHECK: symdef 0: .text abi=0 type=1 size=0 -; CHECK-NEXT: symdef 1: loadg abi=0 type=1 size=8 -; CHECK-NEXT: symdef 2: caller abi=0 type=1 size=8 -; CHECK-NEXT: symdef 3: g abi=0 type=7 size=0 -; CHECK-NEXT: symdef 4: .data abi=0 type=7 size=8 -; CHECK-NEXT: symdef 5: abi=65535 type=3 size=28 -; CHECK-NEXT: symdef 6: abi=65535 type=3 size=28 +; CHECK: symdef-count: 5 +; CHECK: symdef 0: loadg abi=0 type=1 size=8 +; CHECK-NEXT: symdef 1: caller abi=0 type=1 size=8 +; CHECK-NEXT: symdef 2: g abi=0 type=7 size=8 align=8 +; CHECK-NEXT: symdef 3: abi=65535 type=3 size=28 +; CHECK-NEXT: symdef 4: abi=65535 type=3 size=28 ; CHECK: nonpkgdef-count: 12 ; CHECK: nonpkgref-count: 1 ; CHECK-NEXT: nonpkgref 0: ext abi=0 type=0 size=0 -; CHECK: aux 1.0: type=funcinfo target= args=0 locals=0 -; CHECK-NEXT: aux 1.1: type=funcdata target= data=0100000000000000 -; CHECK-NEXT: aux 1.2: type=funcdata target= data=0100000000000000 -; CHECK-NEXT: aux 1.3: type=pcsp target= -; CHECK-NEXT: aux 1.4: type=pcfile target= -; CHECK-NEXT: aux 1.5: type=pcline target= -; CHECK-NEXT: aux 1.6: type=pcdata target= pc= -; CHECK-NEXT: reloc 1.0: off=3 size=4 type=14 add=0 target=g -; CHECK-NEXT: aux 2.7: type=funcinfo target= args=0 locals=8 -; CHECK-NEXT: aux 2.8: type=funcdata target= data=0100000000000000 -; CHECK-NEXT: aux 2.9: type=funcdata target= data=0100000000000000 -; CHECK-NEXT: aux 2.10: type=pcsp target= -; CHECK-NEXT: aux 2.11: type=pcfile target= -; CHECK-NEXT: aux 2.12: type=pcline target= -; CHECK-NEXT: aux 2.13: type=pcdata target= pc= -; CHECK-NEXT: reloc 2.1: off=2 size=4 type=7 add=0 target=ext +; CHECK: aux 0.0: type=funcinfo target= args=0 locals=0 +; CHECK-NEXT: aux 0.1: type=funcdata target= data=0100000000000000 +; CHECK-NEXT: aux 0.2: type=funcdata target= data=0100000000000000 +; CHECK-NEXT: aux 0.3: type=pcsp target= +; CHECK-NEXT: aux 0.4: type=pcfile target= +; CHECK-NEXT: aux 0.5: type=pcline target= +; CHECK-NEXT: aux 0.6: type=pcdata target= pc= +; CHECK-NEXT: reloc 0.0: off=3 size=4 type=14 add=0 target=g +; CHECK-NEXT: aux 1.7: type=funcinfo target= args=0 locals=8 +; CHECK-NEXT: aux 1.8: type=funcdata target= data=0100000000000000 +; CHECK-NEXT: aux 1.9: type=funcdata target= data=0100000000000000 +; CHECK-NEXT: aux 1.10: type=pcsp target= +; CHECK-NEXT: aux 1.11: type=pcfile target= +; CHECK-NEXT: aux 1.12: type=pcline target= +; CHECK-NEXT: aux 1.13: type=pcdata target= pc= +; CHECK-NEXT: reloc 1.1: off=2 size=4 type=7 add=0 target=ext diff --git a/llvm/test/CodeGen/X86/goobj-function-abi.ll b/llvm/test/CodeGen/X86/goobj-function-abi.ll index d6c1e9c6910ba..eb21c1d272029 100644 --- a/llvm/test/CodeGen/X86/goobj-function-abi.ll +++ b/llvm/test/CodeGen/X86/goobj-function-abi.ll @@ -11,10 +11,9 @@ entry: ret void } -; CHECK: symdef-count: 5 -; CHECK: symdef 0: .text abi=0 type=1 size=0 -; CHECK-NEXT: symdef 1: abi0_func abi=0 type=1 size={{[0-9]+}} -; CHECK-NEXT: symdef 2: internal_func abi=1 type=1 size={{[0-9]+}} +; CHECK: symdef-count: 4 +; CHECK: symdef 0: abi0_func abi=0 type=1 size={{[0-9]+}} +; CHECK-NEXT: symdef 1: internal_func abi=1 type=1 size={{[0-9]+}} +; CHECK-NEXT: symdef 2: abi=65535 type=3 size={{[0-9]+}} ; CHECK-NEXT: symdef 3: abi=65535 type=3 size={{[0-9]+}} -; CHECK-NEXT: symdef 4: abi=65535 type=3 size={{[0-9]+}} ; CHECK: nonpkgref {{[0-9]+}}: runtime.morestack_noctxt abi=0 type=0 size=0 diff --git a/llvm/test/CodeGen/X86/goobj-keep-relocation.ll b/llvm/test/CodeGen/X86/goobj-keep-relocation.ll new file mode 100644 index 0000000000000..0dcc4b4c60011 --- /dev/null +++ b/llvm/test/CodeGen/X86/goobj-keep-relocation.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-goobj -filetype=obj < %s -o %t.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.o | FileCheck %s +; RUN: opt -passes='default' -S < %s | llc -mtriple=x86_64-unknown-linux-goobj -filetype=obj -o %t.opt.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.opt.o | FileCheck %s + +@target = constant i8 0, section ".rodata", align 1 +@source = constant i8 0, section ".rodata", align 1 +@llvm.compiler.used = appending global [2 x ptr] [ptr @source, ptr @target], section "llvm.metadata" + +!goobj.keep = !{!0} +!0 = !{ptr @source, ptr @target} + +; CHECK: symdef {{[0-9]+}}: source abi=0 type=3 size=1 +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=0 size=0 type=27 add=0 target=target diff --git a/llvm/test/CodeGen/X86/goobj-marker-relocations.ll b/llvm/test/CodeGen/X86/goobj-marker-relocations.ll new file mode 100644 index 0000000000000..7c1965e3e85db --- /dev/null +++ b/llvm/test/CodeGen/X86/goobj-marker-relocations.ll @@ -0,0 +1,19 @@ +; RUN: llc -mtriple=x86_64-unknown-linux-goobj -filetype=obj < %s -o %t.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.o | FileCheck %s +; RUN: opt -passes='default' -S < %s | llc -mtriple=x86_64-unknown-linux-goobj -filetype=obj -o %t.opt.o +; RUN: %python %S/../../MC/GoObj/Inputs/dump-goobj.py %t.opt.o | FileCheck %s + +@target = constant i8 0, section ".rodata", align 1 +@llvm.compiler.used = appending global [2 x ptr] [ptr @source, ptr @target], section "llvm.metadata" + +define goabiinternal void @source() { + ret void +} + +!goobj.marker_relocs = !{!0, !1} +!0 = !{ptr @source, ptr @target, i32 23, i64 0} +!1 = !{ptr @source, ptr @target, i32 24, i64 96} + +; CHECK: symdef {{[0-9]+}}: source abi=1 type=1 +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=0 size=0 type=23 add=0 target=target +; CHECK: reloc {{[0-9]+}}.{{[0-9]+}}: off=0 size=0 type=24 add=96 target=target diff --git a/llvm/test/MC/GoObj/Inputs/dump-goobj.py b/llvm/test/MC/GoObj/Inputs/dump-goobj.py index ef8e958cedb5e..44cad0694793c 100644 --- a/llvm/test/MC/GoObj/Inputs/dump-goobj.py +++ b/llvm/test/MC/GoObj/Inputs/dump-goobj.py @@ -33,6 +33,7 @@ AUX_SIZE = 9 AUX_TYPES = { + 0: "gotype", 1: "funcinfo", 2: "funcdata", 7: "pcsp", @@ -56,7 +57,10 @@ def read_symbols(data, start, end): "name": string_at(data, offset), "abi": struct.unpack_from("