[mach-o] Add support for -exported_symbols_list and -keep_private_externs

Both options control the final scope of atoms.

When -exported_symbols_list <file> is used, the file is parsed into one
symbol per line in the file.  Only those symbols will be exported (global)
in the final linked image.

The -keep_private_externs option is only used with -r mode. Normally, -r
mode reduces private extern (scopeLinkageUnit) symbols to non-external. But
add the -keep_private_externs option keeps them private external.

llvm-svn: 216146
This commit is contained in:
Nick Kledzik 2014-08-21 01:59:11 +00:00
parent 334e4ffc0d
commit 8c0bf75ef5
10 changed files with 486 additions and 37 deletions

View File

@ -15,6 +15,7 @@
#include "lld/ReaderWriter/Writer.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
@ -25,7 +26,7 @@ using llvm::MachO::HeaderFileType;
namespace lld {
namespace mach_o {
class ArchHandler;
class ArchHandler;
class MachODylibFile;
}
@ -51,6 +52,12 @@ public:
iOS_simulator
};
enum class ExportMode {
globals, // Default, all global symbols exported.
whiteList, // -exported_symbol[s_list], only listed symbols exported.
blackList // -unexported_symbol[s_list], no listed symbol exported.
};
/// Initializes the context to sane default values given the specified output
/// file type, arch, os, and minimum os version. This should be called before
/// other setXXX() methods.
@ -79,6 +86,15 @@ public:
StringRef archName() const { return nameFromArch(_arch); }
OS os() const { return _os; }
ExportMode exportMode() const { return _exportMode; }
void setExportMode(ExportMode mode) { _exportMode = mode; }
void addExportSymbol(StringRef sym);
bool exportRestrictMode() const { return _exportMode != ExportMode::globals; }
bool exportSymbolNamed(StringRef sym) const;
bool keepPrivateExterns() const { return _keepPrivateExterns; }
void setKeepPrivateExterns(bool v) { _keepPrivateExterns = v; }
bool minOS(StringRef mac, StringRef iOS) const;
void setDoNothing(bool value) { _doNothing = value; }
bool doNothing() const { return _doNothing; }
@ -222,6 +238,8 @@ public:
private:
Writer &writer() const override;
mach_o::MachODylibFile* loadIndirectDylib(StringRef path) const;
void checkExportWhiteList(const DefinedAtom *atom) const;
void checkExportBlackList(const DefinedAtom *atom) const;
struct ArchInfo {
@ -258,6 +276,7 @@ private:
bool _deadStrippableDylib;
bool _printAtoms;
bool _testingFileUsage;
bool _keepPrivateExterns;
StringRef _bundleLoader;
mutable std::unique_ptr<mach_o::ArchHandler> _archHandler;
mutable std::unique_ptr<Writer> _writer;
@ -265,6 +284,8 @@ private:
llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
std::set<mach_o::MachODylibFile*> _allDylibs;
mutable std::vector<std::unique_ptr<class MachOFileNode>> _indirectDylibs;
ExportMode _exportMode;
llvm::StringSet<> _exportedSymbols;
};
} // end namespace lld

View File

@ -88,6 +88,31 @@ void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph,
new MachOFileNode(path, forceLoad)));
}
// Export lists are one symbol per line. Blank lines are ignored.
// Trailing comments start with #.
std::error_code parseExportsList(StringRef exportFilePath,
MachOLinkingContext &ctx,
raw_ostream &diagnostics) {
// Map in export list file.
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
MemoryBuffer::getFileOrSTDIN(exportFilePath);
if (std::error_code ec = mb.getError())
return ec;
StringRef buffer = mb->get()->getBuffer();
while (!buffer.empty()) {
// Split off each line in the file.
std::pair<StringRef, StringRef> lineAndRest = buffer.split('\n');
StringRef line = lineAndRest.first;
// Ignore trailing # comments.
std::pair<StringRef, StringRef> symAndComment = line.split('#');
StringRef sym = symAndComment.first.trim();
if (!sym.empty())
ctx.addExportSymbol(sym);
buffer = lineAndRest.second;
}
return std::error_code();
}
//
// There are two variants of the -filelist option:
//
@ -349,7 +374,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
ctx.appendLLVMOption(llvmArg->getValue());
}
// Handle -print_atoms a
// Handle -print_atoms
if (parsedArgs->getLastArg(OPT_print_atoms))
ctx.setPrintAtoms();
@ -357,6 +382,13 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
if (parsedArgs->getLastArg(OPT_t))
ctx.setLogInputFiles(true);
// Handle -keep_private_externs
if (parsedArgs->getLastArg(OPT_keep_private_externs)) {
ctx.setKeepPrivateExterns(true);
if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT)
diagnostics << "warning: -keep_private_externs only used in -r mode\n";
}
// In -test_file_usage mode, we'll be given an explicit list of paths that
// exist. We'll also be expected to print out information about how we located
// libraries and so on that the user specified, but not to actually do any
@ -427,6 +459,64 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
}
}
// Handle -exported_symbols_list <file>
for (auto expFile : parsedArgs->filtered(OPT_exported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
diagnostics << "error: -exported_symbols_list cannot be combined "
<< "with -unexported_symbol[s_list]\n";
return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
diagnostics)) {
diagnostics << "error: " << ec.message()
<< ", processing '-exported_symbols_list "
<< expFile->getValue()
<< "'\n";
return false;
}
}
// Handle -exported_symbol <symbol>
for (auto symbol : parsedArgs->filtered(OPT_exported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) {
diagnostics << "error: -exported_symbol cannot be combined "
<< "with -unexported_symbol[s_list]\n";
return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList);
ctx.addExportSymbol(symbol->getValue());
}
// Handle -unexported_symbols_list <file>
for (auto expFile : parsedArgs->filtered(OPT_unexported_symbols_list)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
diagnostics << "error: -unexported_symbols_list cannot be combined "
<< "with -exported_symbol[s_list]\n";
return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
if (std::error_code ec = parseExportsList(expFile->getValue(), ctx,
diagnostics)) {
diagnostics << "error: " << ec.message()
<< ", processing '-unexported_symbols_list "
<< expFile->getValue()
<< "'\n";
return false;
}
}
// Handle -unexported_symbol <symbol>
for (auto symbol : parsedArgs->filtered(OPT_unexported_symbol)) {
if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) {
diagnostics << "error: -unexported_symbol cannot be combined "
<< "with -exported_symbol[s_list]\n";
return false;
}
ctx.setExportMode(MachOLinkingContext::ExportMode::blackList);
ctx.addExportSymbol(symbol->getValue());
}
// Handle input files
for (auto &arg : *parsedArgs) {
ErrorOr<StringRef> resolvedPath = StringRef();
@ -442,7 +532,8 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
diagnostics << "Unable to find library -l" << arg->getValue() << "\n";
return false;
} else if (ctx.testingFileUsage()) {
diagnostics << "Found library " << canonicalizePath(resolvedPath.get()) << '\n';
diagnostics << "Found library "
<< canonicalizePath(resolvedPath.get()) << '\n';
}
addFile(resolvedPath.get(), inputGraph, globalWholeArchive);
break;
@ -452,7 +543,8 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
diagnostics << "Unable to find -framework " << arg->getValue() << "\n";
return false;
} else if (ctx.testingFileUsage()) {
diagnostics << "Found framework " << canonicalizePath(resolvedPath.get()) << '\n';
diagnostics << "Found framework "
<< canonicalizePath(resolvedPath.get()) << '\n';
}
addFile(resolvedPath.get(), inputGraph, globalWholeArchive);
break;

View File

@ -34,6 +34,21 @@ def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
def mllvm : Separate<["-"], "mllvm">,
MetaVarName<"<option>">,
HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
def exported_symbols_list : Separate<["-"], "exported_symbols_list">,
MetaVarName<"<file-path>">,
HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
def exported_symbol : Separate<["-"], "exported_symbol">,
MetaVarName<"<symbol>">,
HelpText<"Restricts which symbols will be exported">, Group<grp_opts>;
def unexported_symbols_list : Separate<["-"], "unexported_symbols_list">,
MetaVarName<"<file-path>">,
HelpText<"Lists symbols that should not be exported">, Group<grp_opts>;
def unexported_symbol : Separate<["-"], "unexported_symbol">,
MetaVarName<"<symbol>">,
HelpText<"A symbol which should not be exported">, Group<grp_opts>;
def keep_private_externs : Flag<["-"], "keep_private_externs">,
HelpText<"Private extern (hidden) symbols should not be transformed "
"into local symbols">, Group<grp_opts>;
// main executable options
def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;

View File

@ -130,7 +130,8 @@ MachOLinkingContext::MachOLinkingContext()
_doNothing(false), _arch(arch_unknown), _os(OS::macOSX), _osMinVersion(0),
_pageZeroSize(0), _pageSize(4096), _compatibilityVersion(0),
_currentVersion(0), _deadStrippableDylib(false), _printAtoms(false),
_testingFileUsage(false), _archHandler(nullptr) {}
_testingFileUsage(false), _keepPrivateExterns(false),
_archHandler(nullptr), _exportMode(ExportMode::globals) {}
MachOLinkingContext::~MachOLinkingContext() {}
@ -448,6 +449,12 @@ bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) {
return false;
}
// If -exported_symbols_list used, all exported symbols must be defined.
if (_exportMode == ExportMode::whiteList) {
for (const auto &symbol : _exportedSymbols)
addInitialUndefinedSymbol(symbol.getKey());
}
return true;
}
@ -572,4 +579,23 @@ bool MachOLinkingContext::sectionAligned(StringRef seg, StringRef sect,
return false;
}
void MachOLinkingContext::addExportSymbol(StringRef sym) {
// FIXME: Support wildcards.
_exportedSymbols.insert(sym);
}
bool MachOLinkingContext::exportSymbolNamed(StringRef sym) const {
switch (_exportMode) {
case ExportMode::globals:
llvm_unreachable("exportSymbolNamed() should not be called in this mode");
break;
case ExportMode::whiteList:
return _exportedSymbols.count(sym);
case ExportMode::blackList:
return !_exportedSymbols.count(sym);
}
}
} // end namespace lld

View File

@ -106,7 +106,7 @@ public:
void copySectionInfo(NormalizedFile &file);
void updateSectionInfo(NormalizedFile &file);
void buildAtomToAddressMap();
void addSymbols(const lld::File &atomFile, NormalizedFile &file);
std::error_code addSymbols(const lld::File &atomFile, NormalizedFile &file);
void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file);
void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file);
void addSectionRelocs(const lld::File &, NormalizedFile &file);
@ -130,20 +130,21 @@ private:
void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr);
void layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &);
void copySectionContent(SectionInfo *si, ContentBytes &content);
uint8_t scopeBits(const DefinedAtom* atom);
uint16_t descBits(const DefinedAtom* atom);
int dylibOrdinal(const SharedLibraryAtom *sa);
void segIndexForSection(const SectionInfo *sect,
uint8_t &segmentIndex, uint64_t &segmentStartAddr);
const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom);
const Atom *targetOfStub(const DefinedAtom *stubAtom);
bool belongsInGlobalSymbolsSection(const DefinedAtom* atom);
std::error_code getSymbolTableRegion(const DefinedAtom* atom,
bool &inGlobalsRegion,
SymbolScope &symbolScope);
void appendSection(SectionInfo *si, NormalizedFile &file);
uint32_t sectionIndexForAtom(const Atom *atom);
static uint64_t alignTo(uint64_t value, uint8_t align2);
typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex;
struct AtomAndIndex { const Atom *atom; uint32_t index; };
struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; };
struct AtomSorter {
bool operator()(const AtomAndIndex &left, const AtomAndIndex &right);
};
@ -635,18 +636,6 @@ void Util::buildAtomToAddressMap() {
}
}
uint8_t Util::scopeBits(const DefinedAtom* atom) {
switch (atom->scope()) {
case Atom::scopeTranslationUnit:
return 0;
case Atom::scopeLinkageUnit:
return N_PEXT | N_EXT;
case Atom::scopeGlobal:
return N_EXT;
}
llvm_unreachable("Unknown scope");
}
uint16_t Util::descBits(const DefinedAtom* atom) {
uint16_t desc = 0;
switch (atom->merge()) {
@ -677,16 +666,55 @@ bool Util::AtomSorter::operator()(const AtomAndIndex &left,
}
bool Util::belongsInGlobalSymbolsSection(const DefinedAtom* atom) {
// ScopeLinkageUnit symbols are in globals area of symbol table
// in object files, but in locals area for final linked images.
if (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
return (atom->scope() != Atom::scopeTranslationUnit);
else
return (atom->scope() == Atom::scopeGlobal);
std::error_code Util::getSymbolTableRegion(const DefinedAtom* atom,
bool &inGlobalsRegion,
SymbolScope &scope) {
bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
switch (atom->scope()) {
case Atom::scopeTranslationUnit:
scope = 0;
inGlobalsRegion = false;
return std::error_code();
case Atom::scopeLinkageUnit:
if ((_context.exportMode() == MachOLinkingContext::ExportMode::whiteList)
&& _context.exportSymbolNamed(atom->name())) {
return make_dynamic_error_code(Twine("cannot export hidden symbol ")
+ atom->name());
}
if (rMode) {
if (_context.keepPrivateExterns()) {
// -keep_private_externs means keep in globals region as N_PEXT.
scope = N_PEXT | N_EXT;
inGlobalsRegion = true;
return std::error_code();
}
}
// scopeLinkageUnit symbols are no longer global once linked.
scope = N_PEXT;
inGlobalsRegion = false;
return std::error_code();
case Atom::scopeGlobal:
if (_context.exportRestrictMode()) {
if (_context.exportSymbolNamed(atom->name())) {
scope = N_EXT;
inGlobalsRegion = true;
return std::error_code();
} else {
scope = N_PEXT;
inGlobalsRegion = false;
return std::error_code();
}
} else {
scope = N_EXT;
inGlobalsRegion = true;
return std::error_code();
}
break;
}
}
void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
std::error_code Util::addSymbols(const lld::File &atomFile,
NormalizedFile &file) {
bool rMode = (_context.outputMachOType() == llvm::MachO::MH_OBJECT);
// Mach-O symbol table has three regions: locals, globals, undefs.
@ -697,14 +725,19 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
for (const AtomInfo &info : sect->atomsAndOffsets) {
const DefinedAtom *atom = info.atom;
if (!atom->name().empty()) {
if (belongsInGlobalSymbolsSection(atom)) {
AtomAndIndex ai = { atom, sect->finalSectionIndex };
SymbolScope symbolScope;
bool inGlobalsRegion;
if (auto ec = getSymbolTableRegion(atom, inGlobalsRegion, symbolScope)){
return ec;
}
if (inGlobalsRegion) {
AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope };
globals.push_back(ai);
} else {
Symbol sym;
sym.name = atom->name();
sym.type = N_SECT;
sym.scope = scopeBits(atom);
sym.scope = symbolScope;
sym.sect = sect->finalSectionIndex;
sym.desc = descBits(atom);
sym.value = _atomToAddress[atom];
@ -737,7 +770,7 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
Symbol sym;
sym.name = ai.atom->name();
sym.type = N_SECT;
sym.scope = scopeBits(static_cast<const DefinedAtom*>(ai.atom));
sym.scope = ai.scope;
sym.sect = ai.index;
sym.desc = descBits(static_cast<const DefinedAtom*>(ai.atom));
sym.value = _atomToAddress[ai.atom];
@ -750,11 +783,11 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
std::vector<AtomAndIndex> undefs;
undefs.reserve(128);
for (const UndefinedAtom *atom : atomFile.undefined()) {
AtomAndIndex ai = { atom, 0 };
AtomAndIndex ai = { atom, 0, N_EXT };
undefs.push_back(ai);
}
for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) {
AtomAndIndex ai = { atom, 0 };
AtomAndIndex ai = { atom, 0, N_EXT };
undefs.push_back(ai);
}
std::sort(undefs.begin(), undefs.end(), AtomSorter());
@ -768,13 +801,15 @@ void Util::addSymbols(const lld::File &atomFile, NormalizedFile &file) {
}
sym.name = ai.atom->name();
sym.type = N_UNDF;
sym.scope = N_EXT;
sym.scope = ai.scope;
sym.sect = 0;
sym.desc = desc;
sym.value = 0;
_atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start;
file.undefinedSymbols.push_back(sym);
}
return std::error_code();
}
const Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) {
@ -1083,7 +1118,9 @@ normalizedFromAtoms(const lld::File &atomFile,
util.buildAtomToAddressMap();
util.updateSectionInfo(normFile);
util.copySectionContent(normFile);
util.addSymbols(atomFile, normFile);
if (auto ec = util.addSymbols(atomFile, normFile)) {
return ec;
}
util.addIndirectSymbols(atomFile, normFile);
util.addRebaseAndBindingInfo(atomFile, normFile);
util.addSectionRelocs(atomFile, normFile);

View File

@ -0,0 +1,6 @@
#
# For use with exported_symbols_list.yaml
#
_foo
_b

View File

@ -0,0 +1,67 @@
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/libSystem.yaml -o %t \
# RUN: -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \
# RUN: llvm-nm -m %t | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/libSystem.yaml -o %t2 \
# RUN: -exported_symbol _foo -exported_symbol _b && \
# RUN: llvm-nm -m %t2 | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/libSystem.yaml -o %t3 \
# RUN: -unexported_symbol _bar -unexported_symbol _a && \
# RUN: llvm-nm -m %t3 | FileCheck %s
#
# Test -exported_symbols_list and -exported_symbol properly changes visibility.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
0x89, 0xE5, 0x5D, 0xC3 ]
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
alignment: 2
address: 0x000000000000000C
content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
global-symbols:
- name: _a
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x000000000000000C
- name: _b
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x0000000000000010
- name: _bar
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000006
- name: _foo
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
...
# CHECK: (__DATA,__data) non-external (was a private external) _a
# CHECK: (__DATA,__data) external _b
# CHECK: (__TEXT,__text) non-external (was a private external) _bar
# CHECK: (__TEXT,__text) external _foo

View File

@ -0,0 +1,67 @@
# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -exported_symbol _bar \
# RUN: && llvm-nm -m %t | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \
# RUN: -exported_symbol _bar && \
# RUN: llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
#
# RUN: not lld -flavor darwin -arch x86_64 -r %s -o %t3 \
# RUN: -exported_symbol _foo 2> %t4
# Test -exported_symbols_list properly changes visibility in -r mode.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
0x89, 0xE5, 0x5D, 0xC3 ]
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
alignment: 2
address: 0x000000000000000C
content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
global-symbols:
- name: _a
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x000000000000000C
- name: _b
type: N_SECT
scope: [ N_EXT, N_PEXT ]
sect: 2
value: 0x0000000000000010
- name: _bar
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000006
- name: _foo
type: N_SECT
scope: [ N_EXT, N_PEXT ]
sect: 1
value: 0x0000000000000000
...
# CHECK: (__DATA,__data) non-external (was a private external) _a
# CHECK: (__DATA,__data) non-external (was a private external) _b
# CHECK: (__TEXT,__text) external _bar
# CHECK: (__TEXT,__text) non-external (was a private external) _foo
# CHECK_KPE: (__DATA,__data) non-external (was a private external) _a
# CHECK_KPE: (__DATA,__data) private external _b
# CHECK_KPE: (__TEXT,__text) external _bar
# CHECK_KPE: (__TEXT,__text) private external _foo

View File

@ -0,0 +1,55 @@
# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
# RUN: %s %p/Inputs/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2
#
# Test -exported_symbol fails if exported symbol not found.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
0x89, 0xE5, 0x5D, 0xC3 ]
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
alignment: 2
address: 0x000000000000000C
content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
global-symbols:
- name: _a
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x000000000000000C
- name: _b
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x0000000000000010
- name: _bar
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000006
- name: _foo
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000000
...
# CHECK: (__DATA,__data) private external _a
# CHECK: (__DATA,__data) external _b
# CHECK: (__TEXT,__text) private external _bar
# CHECK: (__TEXT,__text) external _foo

View File

@ -0,0 +1,63 @@
# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t \
# RUN: && llvm-nm -m %t | FileCheck %s
#
# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \
# RUN: && llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s
#
# Test -keep_private_externs in -r mode.
#
--- !mach-o
arch: x86_64
file-type: MH_OBJECT
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
sections:
- segment: __TEXT
section: __text
type: S_REGULAR
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
address: 0x0000000000000000
content: [ 0x55, 0x48, 0x89, 0xE5, 0x5D, 0xC3, 0x55, 0x48,
0x89, 0xE5, 0x5D, 0xC3 ]
- segment: __DATA
section: __data
type: S_REGULAR
attributes: [ ]
alignment: 2
address: 0x000000000000000C
content: [ 0x0A, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 ]
global-symbols:
- name: _a
type: N_SECT
scope: [ N_EXT ]
sect: 2
value: 0x000000000000000C
- name: _b
type: N_SECT
scope: [ N_EXT, N_PEXT ]
sect: 2
value: 0x0000000000000010
- name: _bar
type: N_SECT
scope: [ N_EXT ]
sect: 1
value: 0x0000000000000006
- name: _foo
type: N_SECT
scope: [ N_EXT, N_PEXT ]
sect: 1
value: 0x0000000000000000
...
# CHECK: (__DATA,__data) external _a
# CHECK: (__DATA,__data) non-external (was a private external) _b
# CHECK: (__TEXT,__text) external _bar
# CHECK: (__TEXT,__text) non-external (was a private external) _foo
# CHECK_KPE: (__DATA,__data) external _a
# CHECK_KPE: (__DATA,__data) private external _b
# CHECK_KPE: (__TEXT,__text) external _bar
# CHECK_KPE: (__TEXT,__text) private external _foo