forked from OSchip/llvm-project
[JITLink][COFF] Implement include/alternatename linker directive.
Implements include/alternatename linker directive. Alternatename is used by static msvc runtime library. Alias symbol is technically incorrect (we have to search for external definition) but we don't have a way to represent this in jitlink/orc yet, this is solved in the following up patch. Inlcude linker directive is used in ucrt to forcelly lookup the static initializer symbols so that they will be emitted. It's implemented as extenral symbols with live flag on that cause the lookup of these symbols. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D130276
This commit is contained in:
parent
a8f2e24e48
commit
88181375a3
|
@ -1,3 +1,7 @@
|
|||
set(LLVM_TARGET_DEFINITIONS COFFOptions.td)
|
||||
tablegen(LLVM COFFOptions.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(JITLinkTableGen)
|
||||
|
||||
add_llvm_component_library(LLVMJITLink
|
||||
DWARFRecordSectionSplitter.cpp
|
||||
EHFrameSupport.cpp
|
||||
|
@ -23,6 +27,7 @@ add_llvm_component_library(LLVMJITLink
|
|||
|
||||
# COFF
|
||||
COFF.cpp
|
||||
COFFDirectiveParser.cpp
|
||||
COFFLinkGraphBuilder.cpp
|
||||
COFF_x86_64.cpp
|
||||
|
||||
|
@ -36,10 +41,12 @@ add_llvm_component_library(LLVMJITLink
|
|||
|
||||
DEPENDS
|
||||
intrinsics_gen
|
||||
JITLinkTableGen
|
||||
|
||||
LINK_COMPONENTS
|
||||
BinaryFormat
|
||||
Object
|
||||
Option
|
||||
OrcTargetProcess
|
||||
Support
|
||||
)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
//===-- COFFDirectiveParser.cpp - JITLink coff directive parser --*- C++ -*===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// MSVC COFF directive parser
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "COFFDirectiveParser.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace jitlink;
|
||||
|
||||
#define DEBUG_TYPE "jitlink"
|
||||
|
||||
// Create prefix string literals used in Options.td
|
||||
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
|
||||
#include "COFFOptions.inc"
|
||||
#undef PREFIX
|
||||
|
||||
// Create table mapping all options defined in COFFOptions.td
|
||||
static const opt::OptTable::Info infoTable[] = {
|
||||
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12) \
|
||||
{X1, \
|
||||
X2, \
|
||||
X10, \
|
||||
X11, \
|
||||
COFF_OPT_##ID, \
|
||||
opt::Option::KIND##Class, \
|
||||
X9, \
|
||||
X8, \
|
||||
COFF_OPT_##GROUP, \
|
||||
COFF_OPT_##ALIAS, \
|
||||
X7, \
|
||||
X12},
|
||||
#include "COFFOptions.inc"
|
||||
#undef OPTION
|
||||
};
|
||||
|
||||
class COFFOptTable : public opt::OptTable {
|
||||
public:
|
||||
COFFOptTable() : OptTable(infoTable, true) {}
|
||||
};
|
||||
|
||||
static COFFOptTable optTable;
|
||||
|
||||
Expected<std::unique_ptr<opt::InputArgList>>
|
||||
COFFDirectiveParser::parse(StringRef Str) {
|
||||
SmallVector<StringRef, 16> Tokens;
|
||||
SmallVector<const char *, 16> Buffer;
|
||||
cl::TokenizeWindowsCommandLineNoCopy(Str, saver, Tokens);
|
||||
for (StringRef Tok : Tokens) {
|
||||
bool HasNul = Tok.end() != Str.end() && Tok.data()[Tok.size()] == '\0';
|
||||
Buffer.push_back(HasNul ? Tok.data() : saver.save(Tok).data());
|
||||
}
|
||||
|
||||
unsigned missingIndex;
|
||||
unsigned missingCount;
|
||||
|
||||
auto Result = std::make_unique<opt::InputArgList>(
|
||||
optTable.ParseArgs(Buffer, missingIndex, missingCount));
|
||||
|
||||
if (missingCount)
|
||||
return make_error<JITLinkError>(Twine("COFF directive parsing failed: ") +
|
||||
Result->getArgString(missingIndex) +
|
||||
" missing argument");
|
||||
LLVM_DEBUG({
|
||||
for (auto *arg : Result->filtered(COFF_OPT_UNKNOWN))
|
||||
dbgs() << "Unknown coff option argument: " << arg->getAsString(*Result)
|
||||
<< "\n";
|
||||
});
|
||||
return Result;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
//===--- COFFDirectiveParser.h - JITLink coff directive parser --*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// MSVC COFF directive parser
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_JITLINK_COFFDIRECTIVEPARSER_H
|
||||
#define LLVM_EXECUTIONENGINE_JITLINK_COFFDIRECTIVEPARSER_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/StringSaver.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace jitlink {
|
||||
|
||||
enum {
|
||||
COFF_OPT_INVALID = 0,
|
||||
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) COFF_OPT_##ID,
|
||||
#include "COFFOptions.inc"
|
||||
#undef OPTION
|
||||
};
|
||||
|
||||
/// Parser for the MSVC specific preprocessor directives.
|
||||
/// https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160
|
||||
class COFFDirectiveParser {
|
||||
public:
|
||||
Expected<std::unique_ptr<opt::InputArgList>> parse(StringRef Str);
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator bAlloc;
|
||||
llvm::StringSaver saver{bAlloc};
|
||||
};
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_JITLINK_COFFDIRECTIVEPARSER_H
|
|
@ -170,11 +170,16 @@ Error COFFLinkGraphBuilder::graphifySections() {
|
|||
if (auto Err = Obj.getSectionContents(*Sec, Data))
|
||||
return Err;
|
||||
|
||||
auto CharData = ArrayRef<char>(
|
||||
reinterpret_cast<const char *>(Data.data()), Data.size());
|
||||
|
||||
if (SectionName == getDirectiveSectionName())
|
||||
if (auto Err = handleDirectiveSection(
|
||||
StringRef(CharData.data(), CharData.size())))
|
||||
return Err;
|
||||
|
||||
B = &G->createContentBlock(
|
||||
*GraphSec,
|
||||
ArrayRef<char>(reinterpret_cast<const char *>(Data.data()),
|
||||
Data.size()),
|
||||
orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
|
||||
*GraphSec, CharData, orc::ExecutorAddr(getSectionAddress(Obj, *Sec)),
|
||||
(*Sec)->getAlignment(), 0);
|
||||
}
|
||||
|
||||
|
@ -224,30 +229,17 @@ Error COFFLinkGraphBuilder::graphifySymbols() {
|
|||
<< " (index: " << SectionIndex << ") \n";
|
||||
});
|
||||
else if (Sym->isUndefined()) {
|
||||
auto CreateExternalSymbol = [&](StringRef SymbolName) {
|
||||
if (!ExternalSymbols.count(SymbolName))
|
||||
ExternalSymbols[SymbolName] = &G->addExternalSymbol(
|
||||
SymbolName, Sym->getValue(), Linkage::Strong);
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << " " << SymIndex
|
||||
<< ": Creating external graph symbol for COFF symbol \""
|
||||
<< SymbolName << "\" in "
|
||||
<< getCOFFSectionName(SectionIndex, Sec, *Sym)
|
||||
<< " (index: " << SectionIndex << ") \n";
|
||||
});
|
||||
return ExternalSymbols[SymbolName];
|
||||
};
|
||||
if (SymbolName.startswith(getDLLImportStubPrefix())) {
|
||||
if (Sym->getValue() != 0)
|
||||
return make_error<JITLinkError>(
|
||||
"DLL import symbol has non-zero offset");
|
||||
|
||||
auto ExternalSym = CreateExternalSymbol(
|
||||
SymbolName.drop_front(getDLLImportStubPrefix().size()));
|
||||
auto ExternalSym = createExternalSymbol(
|
||||
SymIndex, SymbolName.drop_front(getDLLImportStubPrefix().size()),
|
||||
*Sym, Sec);
|
||||
GSym = &createDLLImportEntry(SymbolName, *ExternalSym);
|
||||
} else
|
||||
GSym = CreateExternalSymbol(SymbolName);
|
||||
GSym = createExternalSymbol(SymIndex, SymbolName, *Sym, Sec);
|
||||
} else if (Sym->isWeakExternal()) {
|
||||
auto *WeakExternal = Sym->getAux<object::coff_aux_weak_external>();
|
||||
COFFSymbolIndex TagIndex = WeakExternal->TagIndex;
|
||||
|
@ -281,12 +273,52 @@ Error COFFLinkGraphBuilder::graphifySymbols() {
|
|||
if (auto Err = flushWeakAliasRequests())
|
||||
return Err;
|
||||
|
||||
if (auto Err = handleAlternateNames())
|
||||
return Err;
|
||||
|
||||
if (auto Err = calculateImplicitSizeOfSymbols())
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error COFFLinkGraphBuilder::handleDirectiveSection(StringRef Str) {
|
||||
auto Parsed = DirectiveParser.parse(Str);
|
||||
if (!Parsed)
|
||||
return Parsed.takeError();
|
||||
for (auto *Arg : **Parsed) {
|
||||
StringRef S = Arg->getValue();
|
||||
switch (Arg->getOption().getID()) {
|
||||
case COFF_OPT_alternatename: {
|
||||
StringRef From, To;
|
||||
std::tie(From, To) = S.split('=');
|
||||
if (From.empty() || To.empty())
|
||||
return make_error<JITLinkError>(
|
||||
"Invalid COFF /alternatename directive");
|
||||
AlternateNames[From] = To;
|
||||
break;
|
||||
}
|
||||
case COFF_OPT_incl: {
|
||||
auto DataCopy = G->allocateString(S);
|
||||
StringRef StrCopy(DataCopy.data(), DataCopy.size());
|
||||
ExternalSymbols[StrCopy] =
|
||||
&G->addExternalSymbol(StrCopy, 0, Linkage::Strong);
|
||||
ExternalSymbols[StrCopy]->setLive(true);
|
||||
break;
|
||||
}
|
||||
case COFF_OPT_export:
|
||||
break;
|
||||
default: {
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Unknown coff directive: " << Arg->getSpelling() << "\n";
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
|
||||
// Export the weak external symbols and alias it
|
||||
for (auto &WeakExternal : WeakExternalRequests) {
|
||||
|
@ -303,22 +335,18 @@ Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
|
|||
? Scope::Default
|
||||
: Scope::Local;
|
||||
|
||||
// FIXME: Support this when there's a way to handle this.
|
||||
if (!Target->isDefined())
|
||||
return make_error<JITLinkError>("Weak external symbol with external "
|
||||
"symbol as alternative not supported.");
|
||||
|
||||
jitlink::Symbol *NewSymbol = &G->addDefinedSymbol(
|
||||
Target->getBlock(), Target->getOffset(), WeakExternal.SymbolName,
|
||||
Target->getSize(), Linkage::Weak, S, Target->isCallable(), false);
|
||||
auto NewSymbol =
|
||||
createAliasSymbol(WeakExternal.SymbolName, Linkage::Weak, S, *Target);
|
||||
if (!NewSymbol)
|
||||
return NewSymbol.takeError();
|
||||
setGraphSymbol(AliasSymbol->getSectionNumber(), WeakExternal.Alias,
|
||||
*NewSymbol);
|
||||
**NewSymbol);
|
||||
LLVM_DEBUG({
|
||||
dbgs() << " " << WeakExternal.Alias
|
||||
<< ": Creating weak external symbol for COFF symbol \""
|
||||
<< WeakExternal.SymbolName << "\" in section "
|
||||
<< AliasSymbol->getSectionNumber() << "\n";
|
||||
dbgs() << " " << *NewSymbol << "\n";
|
||||
dbgs() << " " << **NewSymbol << "\n";
|
||||
});
|
||||
} else
|
||||
return make_error<JITLinkError>("Weak symbol alias requested but actual "
|
||||
|
@ -328,6 +356,49 @@ Error COFFLinkGraphBuilder::flushWeakAliasRequests() {
|
|||
return Error::success();
|
||||
}
|
||||
|
||||
Error COFFLinkGraphBuilder::handleAlternateNames() {
|
||||
// FIXME: Use proper alias
|
||||
for (auto &KeyValue : AlternateNames)
|
||||
if (DefinedSymbols.count(KeyValue.second) &&
|
||||
ExternalSymbols.count(KeyValue.first)) {
|
||||
auto *Target = DefinedSymbols[KeyValue.second];
|
||||
auto *Alias = ExternalSymbols[KeyValue.first];
|
||||
G->makeDefined(*Alias, Target->getBlock(), Target->getOffset(),
|
||||
Target->getSize(), Linkage::Weak, Scope::Local, false);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Symbol *COFFLinkGraphBuilder::createExternalSymbol(
|
||||
COFFSymbolIndex SymIndex, StringRef SymbolName,
|
||||
object::COFFSymbolRef Symbol, const object::coff_section *Section) {
|
||||
if (!ExternalSymbols.count(SymbolName))
|
||||
ExternalSymbols[SymbolName] =
|
||||
&G->addExternalSymbol(SymbolName, Symbol.getValue(), Linkage::Strong);
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << " " << SymIndex
|
||||
<< ": Creating external graph symbol for COFF symbol \""
|
||||
<< SymbolName << "\" in "
|
||||
<< getCOFFSectionName(Symbol.getSectionNumber(), Section, Symbol)
|
||||
<< " (index: " << Symbol.getSectionNumber() << ") \n";
|
||||
});
|
||||
return ExternalSymbols[SymbolName];
|
||||
}
|
||||
|
||||
Expected<Symbol *> COFFLinkGraphBuilder::createAliasSymbol(StringRef SymbolName,
|
||||
Linkage L, Scope S,
|
||||
Symbol &Target) {
|
||||
if (!Target.isDefined()) {
|
||||
// FIXME: Support this when there's a way to handle this.
|
||||
return make_error<JITLinkError>("Weak external symbol with external "
|
||||
"symbol as alternative not supported.");
|
||||
}
|
||||
return &G->addDefinedSymbol(Target.getBlock(), Target.getOffset(), SymbolName,
|
||||
Target.getSize(), L, S, Target.isCallable(),
|
||||
false);
|
||||
}
|
||||
|
||||
// In COFF, most of the defined symbols don't contain the size information.
|
||||
// Hence, we calculate the "implicit" size of symbol by taking the delta of
|
||||
// offsets of consecutive symbols within a block. We maintain a balanced tree
|
||||
|
@ -426,10 +497,11 @@ Expected<Symbol *> COFFLinkGraphBuilder::createDefinedSymbol(
|
|||
if (Symbol.isExternal()) {
|
||||
// This is not a comdat sequence, export the symbol as it is
|
||||
if (!isComdatSection(Section)) {
|
||||
|
||||
return &G->addDefinedSymbol(
|
||||
auto GSym = &G->addDefinedSymbol(
|
||||
*B, Symbol.getValue(), SymbolName, 0, Linkage::Strong, Scope::Default,
|
||||
Symbol.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION, false);
|
||||
DefinedSymbols[SymbolName] = GSym;
|
||||
return GSym;
|
||||
} else {
|
||||
if (!PendingComdatExports[Symbol.getSectionNumber()])
|
||||
return make_error<JITLinkError>("No pending COMDAT export for symbol " +
|
||||
|
@ -557,8 +629,9 @@ COFFLinkGraphBuilder::exportCOMDATSymbol(COFFSymbolIndex SymIndex,
|
|||
dbgs() << " " << *Target << "\n";
|
||||
});
|
||||
PendingComdatExport = None;
|
||||
DefinedSymbols[SymbolName] = Target;
|
||||
return Target;
|
||||
}
|
||||
|
||||
} // namespace jitlink
|
||||
} // namespace llvm
|
||||
} // namespace llvm
|
|
@ -18,6 +18,7 @@
|
|||
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
|
||||
#include "COFFDirectiveParser.h"
|
||||
#include "EHFrameSupportImpl.h"
|
||||
#include "JITLinkGeneric.h"
|
||||
|
||||
|
@ -133,6 +134,11 @@ private:
|
|||
|
||||
Section &getCommonSection();
|
||||
|
||||
Symbol *createExternalSymbol(COFFSymbolIndex SymIndex, StringRef SymbolName,
|
||||
object::COFFSymbolRef Symbol,
|
||||
const object::coff_section *Section);
|
||||
Expected<Symbol *> createAliasSymbol(StringRef SymbolName, Linkage L, Scope S,
|
||||
Symbol &Target);
|
||||
Expected<Symbol *> createDefinedSymbol(COFFSymbolIndex SymIndex,
|
||||
StringRef SymbolName,
|
||||
object::COFFSymbolRef Symbol,
|
||||
|
@ -143,7 +149,10 @@ private:
|
|||
Expected<Symbol *> exportCOMDATSymbol(COFFSymbolIndex SymIndex,
|
||||
StringRef SymbolName,
|
||||
object::COFFSymbolRef Symbol);
|
||||
|
||||
Error handleDirectiveSection(StringRef Str);
|
||||
Error flushWeakAliasRequests();
|
||||
Error handleAlternateNames();
|
||||
Error calculateImplicitSizeOfSymbols();
|
||||
|
||||
static uint64_t getSectionAddress(const object::COFFObjectFile &Obj,
|
||||
|
@ -154,18 +163,22 @@ private:
|
|||
static unsigned getPointerSize(const object::COFFObjectFile &Obj);
|
||||
static support::endianness getEndianness(const object::COFFObjectFile &Obj);
|
||||
static StringRef getDLLImportStubPrefix() { return "__imp_"; }
|
||||
static StringRef getDirectiveSectionName() { return ".drectve"; }
|
||||
StringRef getCOFFSectionName(COFFSectionIndex SectionIndex,
|
||||
const object::coff_section *Sec,
|
||||
object::COFFSymbolRef Sym);
|
||||
|
||||
const object::COFFObjectFile &Obj;
|
||||
std::unique_ptr<LinkGraph> G;
|
||||
COFFDirectiveParser DirectiveParser;
|
||||
|
||||
Section *CommonSection = nullptr;
|
||||
std::vector<Block *> GraphBlocks;
|
||||
std::vector<Symbol *> GraphSymbols;
|
||||
|
||||
DenseMap<StringRef, StringRef> AlternateNames;
|
||||
DenseMap<StringRef, Symbol *> ExternalSymbols;
|
||||
DenseMap<StringRef, Symbol *> DefinedSymbols;
|
||||
};
|
||||
|
||||
template <typename RelocHandlerFunction>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
include "llvm/Option/OptParser.td"
|
||||
|
||||
// link.exe accepts options starting with either a dash or a slash.
|
||||
|
||||
// Flag that takes no arguments.
|
||||
class F<string name> : Flag<["/", "-", "/?", "-?"], name>;
|
||||
|
||||
// Flag that takes one argument after ":".
|
||||
class P<string name> :
|
||||
Joined<["/", "-", "/?", "-?"], name#":">;
|
||||
|
||||
// Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the
|
||||
// flag on and using it suffixed by ":no" turns it off.
|
||||
multiclass B_priv<string name> {
|
||||
def "" : F<name>;
|
||||
def _no : F<name#":no">;
|
||||
}
|
||||
|
||||
def export : P<"export">;
|
||||
def alternatename : P<"alternatename">;
|
||||
def incl : Joined<["/", "-", "/?", "-?"], "include:">;
|
|
@ -0,0 +1,30 @@
|
|||
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t
|
||||
# RUN: llvm-jitlink -noexec %t
|
||||
#
|
||||
# Check object with alternatename directive does not fail, because
|
||||
# foo external symbol was resolved to foo_def.
|
||||
#
|
||||
|
||||
.text
|
||||
|
||||
.def foo_def;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl foo_def
|
||||
.p2align 4, 0x90
|
||||
foo_def:
|
||||
retq
|
||||
|
||||
.def main;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl main
|
||||
.p2align 4, 0x90
|
||||
main:
|
||||
callq foo
|
||||
retq
|
||||
|
||||
.section .drectve,"yn"
|
||||
.ascii "/alternatename:foo=foo_def"
|
|
@ -0,0 +1,27 @@
|
|||
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t
|
||||
# RUN: not llvm-jitlink -noexec %t 2>&1 | FileCheck %s
|
||||
#
|
||||
# Check object without alternatename directive fails because of
|
||||
# external symbol not found error.
|
||||
#
|
||||
# CHECK: error: Symbols not found: [ foo ]
|
||||
.text
|
||||
|
||||
.def foo_def;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl foo_def
|
||||
.p2align 4, 0x90
|
||||
foo_def:
|
||||
retq
|
||||
|
||||
.def main;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl main
|
||||
.p2align 4, 0x90
|
||||
main:
|
||||
callq foo
|
||||
retq
|
|
@ -0,0 +1,21 @@
|
|||
# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc %s -o %t
|
||||
# RUN: not llvm-jitlink -noexec %t 2>&1 | FileCheck %s
|
||||
#
|
||||
# Check an external symbol "foo" is generated and not dead-stripped
|
||||
# because of include directive which turned into symbol not found error.
|
||||
#
|
||||
# CHECK: error: Symbols not found: [ foo ]
|
||||
|
||||
.text
|
||||
|
||||
.def main;
|
||||
.scl 2;
|
||||
.type 32;
|
||||
.endef
|
||||
.globl main
|
||||
.p2align 4, 0x90
|
||||
main:
|
||||
retq
|
||||
|
||||
.section .drectve,"yn"
|
||||
.ascii "/include:foo"
|
Loading…
Reference in New Issue