forked from OSchip/llvm-project
[mach-o] Add support for using export tries
On Darwin at runtime, dyld will prefer to use the export trie of a dylib instead of the traditional symbol table (which is large and requires a binary search). This change enables the linker to generate an export trie and to prefer it if found in a dylib being linked against. This also simples the yaml for dylibs because the yaml form of the trie can be reduced to just a sequence of names. llvm-svn: 217066
This commit is contained in:
parent
ed9709d928
commit
141330aef6
|
|
@ -33,6 +33,7 @@
|
|||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Object/MachO.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
|
@ -45,6 +46,8 @@
|
|||
#include <system_error>
|
||||
|
||||
using namespace llvm::MachO;
|
||||
using llvm::object::ExportEntry;
|
||||
using llvm::object::MachOObjectFile;
|
||||
|
||||
namespace lld {
|
||||
namespace mach_o {
|
||||
|
|
@ -231,6 +234,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
|
|||
|
||||
// Walk load commands looking for segments/sections and the symbol table.
|
||||
const data_in_code_entry *dataInCode = nullptr;
|
||||
const dyld_info_command *dyldInfo = nullptr;
|
||||
uint32_t dataInCodeSize = 0;
|
||||
ec = forEachLoadCommand(lcRange, lcCount, swap, is64,
|
||||
[&] (uint32_t cmd, uint32_t size, const char* lc) -> bool {
|
||||
|
|
@ -406,6 +410,7 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
|
|||
start + read32(swap, ldc->dataoff));
|
||||
dataInCodeSize = read32(swap, ldc->datasize);
|
||||
}
|
||||
break;
|
||||
case LC_LOAD_DYLIB:
|
||||
case LC_LOAD_WEAK_DYLIB:
|
||||
case LC_REEXPORT_DYLIB:
|
||||
|
|
@ -417,6 +422,10 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
|
|||
f->dependentDylibs.push_back(entry);
|
||||
}
|
||||
break;
|
||||
case LC_DYLD_INFO:
|
||||
case LC_DYLD_INFO_ONLY:
|
||||
dyldInfo = reinterpret_cast<const dyld_info_command*>(lc);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -434,11 +443,30 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb,
|
|||
}
|
||||
}
|
||||
|
||||
if (dyldInfo) {
|
||||
// If any exports, extract and add to normalized exportInfo vector.
|
||||
if (dyldInfo->export_size) {
|
||||
const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start +
|
||||
dyldInfo->export_off);
|
||||
ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size);
|
||||
for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) {
|
||||
Export normExport;
|
||||
normExport.name = trieExport.name().copy(f->ownedAllocations);
|
||||
normExport.offset = trieExport.address();
|
||||
normExport.kind = ExportSymbolKind(trieExport.flags() & EXPORT_SYMBOL_FLAGS_KIND_MASK);
|
||||
normExport.flags = trieExport.flags() & ~EXPORT_SYMBOL_FLAGS_KIND_MASK;
|
||||
normExport.otherOffset = trieExport.other();
|
||||
if (!trieExport.otherName().empty())
|
||||
normExport.otherName = trieExport.otherName().copy(f->ownedAllocations);
|
||||
f->exportInfo.push_back(normExport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class MachOReader : public Reader {
|
||||
public:
|
||||
MachOReader(MachOLinkingContext &ctx) : _ctx(ctx) {}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/MachO.h"
|
||||
|
|
@ -77,12 +78,14 @@ private:
|
|||
void writeRebaseInfo();
|
||||
void writeBindingInfo();
|
||||
void writeLazyBindingInfo();
|
||||
void writeExportInfo();
|
||||
void writeDataInCodeInfo();
|
||||
void writeLinkEditContent();
|
||||
void buildLinkEditInfo();
|
||||
void buildRebaseInfo();
|
||||
void buildBindInfo();
|
||||
void buildLazyBindInfo();
|
||||
void buildExportTrie();
|
||||
void computeDataInCodeSize();
|
||||
void computeSymbolTableSizes();
|
||||
void buildSectionRelocations();
|
||||
|
|
@ -115,6 +118,7 @@ private:
|
|||
class ByteBuffer {
|
||||
public:
|
||||
ByteBuffer() : _ostream(_bytes) { }
|
||||
|
||||
void append_byte(uint8_t b) {
|
||||
_ostream << b;
|
||||
}
|
||||
|
|
@ -144,6 +148,37 @@ private:
|
|||
llvm::raw_svector_ostream _ostream;
|
||||
};
|
||||
|
||||
struct TrieNode; // Forward declaration.
|
||||
|
||||
struct TrieEdge {
|
||||
TrieEdge(StringRef s, TrieNode *node) : _subString(s), _child(node) {}
|
||||
~TrieEdge() {}
|
||||
|
||||
StringRef _subString;
|
||||
struct TrieNode *_child;
|
||||
};
|
||||
|
||||
struct TrieNode {
|
||||
TrieNode(StringRef s)
|
||||
: _cummulativeString(s), _address(0), _flags(0), _other(0),
|
||||
_trieOffset(0), _hasExportInfo(false) {}
|
||||
~TrieNode() {}
|
||||
|
||||
void addSymbol(const Export &entry, BumpPtrAllocator &allocator,
|
||||
std::vector<TrieNode *> &allNodes);
|
||||
bool updateOffset(uint32_t &offset);
|
||||
void appendToByteBuffer(ByteBuffer &out);
|
||||
|
||||
private:
|
||||
StringRef _cummulativeString;
|
||||
SmallVector<TrieEdge, 8> _children;
|
||||
uint64_t _address;
|
||||
uint64_t _flags;
|
||||
uint64_t _other;
|
||||
StringRef _importedName;
|
||||
uint32_t _trieOffset;
|
||||
bool _hasExportInfo;
|
||||
};
|
||||
|
||||
struct SegExtraInfo {
|
||||
uint32_t fileOffset;
|
||||
|
|
@ -190,6 +225,8 @@ private:
|
|||
uint32_t _endOfBindingInfo;
|
||||
uint32_t _startOfLazyBindingInfo;
|
||||
uint32_t _endOfLazyBindingInfo;
|
||||
uint32_t _startOfExportTrie;
|
||||
uint32_t _endOfExportTrie;
|
||||
uint32_t _endOfLinkEdit;
|
||||
uint64_t _addressOfLinkEdit;
|
||||
SegMap _segInfo;
|
||||
|
|
@ -198,7 +235,7 @@ private:
|
|||
ByteBuffer _bindingInfo;
|
||||
ByteBuffer _lazyBindingInfo;
|
||||
ByteBuffer _weakBindingInfo;
|
||||
ByteBuffer _exportInfo;
|
||||
ByteBuffer _exportTrie;
|
||||
};
|
||||
|
||||
size_t headerAndLoadCommandsSize(const NormalizedFile &file) {
|
||||
|
|
@ -295,7 +332,9 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
|
|||
_endOfBindingInfo = _startOfBindingInfo + _bindingInfo.size();
|
||||
_startOfLazyBindingInfo = _endOfBindingInfo;
|
||||
_endOfLazyBindingInfo = _startOfLazyBindingInfo + _lazyBindingInfo.size();
|
||||
_startOfDataInCode = _endOfLazyBindingInfo;
|
||||
_startOfExportTrie = _endOfLazyBindingInfo;
|
||||
_endOfExportTrie = _startOfExportTrie + _exportTrie.size();
|
||||
_startOfDataInCode = _endOfExportTrie;
|
||||
_startOfSymbols = _startOfDataInCode + _dataInCodeSize;
|
||||
_startOfIndirectSymbols = _startOfSymbols + _symbolTableSize;
|
||||
_startOfSymbolStrings = _startOfIndirectSymbols
|
||||
|
|
@ -315,6 +354,8 @@ MachOFileLayout::MachOFileLayout(const NormalizedFile &file)
|
|||
<< " endOfBindingInfo=" << _endOfBindingInfo << "\n"
|
||||
<< " startOfLazyBindingInfo=" << _startOfLazyBindingInfo << "\n"
|
||||
<< " endOfLazyBindingInfo=" << _endOfLazyBindingInfo << "\n"
|
||||
<< " startOfExportTrie=" << _startOfExportTrie << "\n"
|
||||
<< " endOfExportTrie=" << _endOfExportTrie << "\n"
|
||||
<< " startOfDataInCode=" << _startOfDataInCode << "\n"
|
||||
<< " startOfSymbols=" << _startOfSymbols << "\n"
|
||||
<< " startOfSymbolStrings=" << _startOfSymbolStrings << "\n"
|
||||
|
|
@ -685,8 +726,8 @@ std::error_code MachOFileLayout::writeLoadCommands() {
|
|||
di->weak_bind_size = 0;
|
||||
di->lazy_bind_off = _lazyBindingInfo.size() ? _startOfLazyBindingInfo : 0;
|
||||
di->lazy_bind_size = _lazyBindingInfo.size();
|
||||
di->export_off = 0;
|
||||
di->export_size = 0;
|
||||
di->export_off = _exportTrie.size() ? _startOfExportTrie : 0;
|
||||
di->export_size = _exportTrie.size();
|
||||
if (_swap)
|
||||
swapStruct(*di);
|
||||
lc += sizeof(dyld_info_command);
|
||||
|
|
@ -897,10 +938,15 @@ void MachOFileLayout::writeLazyBindingInfo() {
|
|||
_lazyBindingInfo.bytes(), _lazyBindingInfo.size());
|
||||
}
|
||||
|
||||
void MachOFileLayout::writeExportInfo() {
|
||||
memcpy(&_buffer[_startOfExportTrie], _exportTrie.bytes(), _exportTrie.size());
|
||||
}
|
||||
|
||||
void MachOFileLayout::buildLinkEditInfo() {
|
||||
buildRebaseInfo();
|
||||
buildBindInfo();
|
||||
buildLazyBindInfo();
|
||||
buildExportTrie();
|
||||
computeSymbolTableSizes();
|
||||
computeDataInCodeSize();
|
||||
}
|
||||
|
|
@ -957,6 +1003,191 @@ void MachOFileLayout::buildLazyBindInfo() {
|
|||
_lazyBindingInfo.align(_is64 ? 8 : 4);
|
||||
}
|
||||
|
||||
void MachOFileLayout::TrieNode::addSymbol(const Export& entry,
|
||||
BumpPtrAllocator &allocator,
|
||||
std::vector<TrieNode*> &allNodes) {
|
||||
StringRef partialStr = entry.name.drop_front(_cummulativeString.size());
|
||||
for (TrieEdge &edge : _children) {
|
||||
StringRef edgeStr = edge._subString;
|
||||
if (partialStr.startswith(edgeStr)) {
|
||||
// Already have matching edge, go down that path.
|
||||
edge._child->addSymbol(entry, allocator, allNodes);
|
||||
return;
|
||||
}
|
||||
// See if string has commmon prefix with existing edge.
|
||||
for (int n=edgeStr.size()-1; n > 0; --n) {
|
||||
if (partialStr.substr(0, n).equals(edgeStr.substr(0, n))) {
|
||||
// Splice in new node: was A -> C, now A -> B -> C
|
||||
StringRef bNodeStr = edge._child->_cummulativeString;
|
||||
bNodeStr = bNodeStr.drop_back(edgeStr.size()-n).copy(allocator);
|
||||
TrieNode* bNode = new (allocator) TrieNode(bNodeStr);
|
||||
allNodes.push_back(bNode);
|
||||
TrieNode* cNode = edge._child;
|
||||
StringRef abEdgeStr = edgeStr.substr(0,n).copy(allocator);
|
||||
StringRef bcEdgeStr = edgeStr.substr(n).copy(allocator);
|
||||
DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
|
||||
<< "splice in TrieNode('" << bNodeStr
|
||||
<< "') between edge '"
|
||||
<< abEdgeStr << "' and edge='"
|
||||
<< bcEdgeStr<< "'\n");
|
||||
TrieEdge& abEdge = edge;
|
||||
abEdge._subString = abEdgeStr;
|
||||
abEdge._child = bNode;
|
||||
TrieEdge bcEdge(bcEdgeStr, cNode);
|
||||
bNode->_children.push_back(bcEdge);
|
||||
bNode->addSymbol(entry, allocator, allNodes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
|
||||
assert(entry.otherOffset != 0);
|
||||
}
|
||||
if (entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
|
||||
assert(entry.otherOffset != 0);
|
||||
}
|
||||
// No commonality with any existing child, make a new edge.
|
||||
TrieNode* newNode = new (allocator) TrieNode(entry.name.copy(allocator));
|
||||
TrieEdge newEdge(partialStr, newNode);
|
||||
_children.push_back(newEdge);
|
||||
DEBUG_WITH_TYPE("trie-builder", llvm::dbgs()
|
||||
<< "new TrieNode('" << entry.name << "') with edge '"
|
||||
<< partialStr << "' from node='"
|
||||
<< _cummulativeString << "'\n");
|
||||
newNode->_address = entry.offset;
|
||||
newNode->_flags = entry.flags | entry.kind;
|
||||
newNode->_other = entry.otherOffset;
|
||||
if ((entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) && !entry.otherName.empty())
|
||||
newNode->_importedName = entry.otherName.copy(allocator);
|
||||
newNode->_hasExportInfo = true;
|
||||
allNodes.push_back(newNode);
|
||||
}
|
||||
|
||||
bool MachOFileLayout::TrieNode::updateOffset(uint32_t& offset) {
|
||||
uint32_t nodeSize = 1; // Length when no export info
|
||||
if (_hasExportInfo) {
|
||||
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
|
||||
nodeSize = llvm::getULEB128Size(_flags);
|
||||
nodeSize += llvm::getULEB128Size(_other); // Other contains ordinal.
|
||||
nodeSize += _importedName.size();
|
||||
++nodeSize; // Trailing zero in imported name.
|
||||
} else {
|
||||
nodeSize = llvm::getULEB128Size(_flags) + llvm::getULEB128Size(_address);
|
||||
if (_flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
|
||||
nodeSize += llvm::getULEB128Size(_other);
|
||||
}
|
||||
// Overall node size so far is uleb128 of export info + actual export info.
|
||||
nodeSize += llvm::getULEB128Size(nodeSize);
|
||||
}
|
||||
// Compute size of all child edges.
|
||||
++nodeSize; // Byte for number of chidren.
|
||||
for (TrieEdge &edge : _children) {
|
||||
nodeSize += edge._subString.size() + 1 // String length.
|
||||
+ llvm::getULEB128Size(edge._child->_trieOffset); // Offset len.
|
||||
}
|
||||
// On input, 'offset' is new prefered location for this node.
|
||||
bool result = (_trieOffset != offset);
|
||||
// Store new location in node object for use by parents.
|
||||
_trieOffset = offset;
|
||||
// Update offset for next iteration.
|
||||
offset += nodeSize;
|
||||
// Return true if _trieOffset was changed.
|
||||
return result;
|
||||
}
|
||||
|
||||
void MachOFileLayout::TrieNode::appendToByteBuffer(ByteBuffer &out) {
|
||||
if (_hasExportInfo) {
|
||||
if (_flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
|
||||
if (!_importedName.empty()) {
|
||||
// nodes with re-export info: size, flags, ordinal, import-name
|
||||
uint32_t nodeSize = llvm::getULEB128Size(_flags)
|
||||
+ llvm::getULEB128Size(_other)
|
||||
+ _importedName.size() + 1;
|
||||
assert(nodeSize < 256);
|
||||
out.append_byte(nodeSize);
|
||||
out.append_uleb128(_flags);
|
||||
out.append_uleb128(_other);
|
||||
out.append_string(_importedName);
|
||||
} else {
|
||||
// nodes without re-export info: size, flags, ordinal, empty-string
|
||||
uint32_t nodeSize = llvm::getULEB128Size(_flags)
|
||||
+ llvm::getULEB128Size(_other) + 1;
|
||||
assert(nodeSize < 256);
|
||||
out.append_byte(nodeSize);
|
||||
out.append_uleb128(_flags);
|
||||
out.append_uleb128(_other);
|
||||
out.append_byte(0);
|
||||
}
|
||||
} else if ( _flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
|
||||
// Nodes with export info: size, flags, address, other
|
||||
uint32_t nodeSize = llvm::getULEB128Size(_flags)
|
||||
+ llvm::getULEB128Size(_address)
|
||||
+ llvm::getULEB128Size(_other);
|
||||
assert(nodeSize < 256);
|
||||
out.append_byte(nodeSize);
|
||||
out.append_uleb128(_flags);
|
||||
out.append_uleb128(_address);
|
||||
out.append_uleb128(_other);
|
||||
} else {
|
||||
// Nodes with export info: size, flags, address
|
||||
uint32_t nodeSize = llvm::getULEB128Size(_flags)
|
||||
+ llvm::getULEB128Size(_address);
|
||||
assert(nodeSize < 256);
|
||||
out.append_byte(nodeSize);
|
||||
out.append_uleb128(_flags);
|
||||
out.append_uleb128(_address);
|
||||
}
|
||||
} else {
|
||||
// Node with no export info.
|
||||
uint32_t nodeSize = 0;
|
||||
out.append_byte(nodeSize);
|
||||
}
|
||||
// Add number of children.
|
||||
assert(_children.size() < 256);
|
||||
out.append_byte(_children.size());
|
||||
// Append each child edge substring and node offset.
|
||||
for (TrieEdge &edge : _children) {
|
||||
out.append_string(edge._subString);
|
||||
out.append_uleb128(edge._child->_trieOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void MachOFileLayout::buildExportTrie() {
|
||||
if (_file.exportInfo.empty())
|
||||
return;
|
||||
|
||||
// For all temporary strings and objects used building trie.
|
||||
BumpPtrAllocator allocator;
|
||||
|
||||
// Build trie of all exported symbols.
|
||||
TrieNode* rootNode = new (allocator) TrieNode(StringRef());
|
||||
std::vector<TrieNode*> allNodes;
|
||||
allNodes.reserve(_file.exportInfo.size()*2);
|
||||
allNodes.push_back(rootNode);
|
||||
for (const Export& entry : _file.exportInfo) {
|
||||
rootNode->addSymbol(entry, allocator, allNodes);
|
||||
}
|
||||
|
||||
// Assign each node in the vector an offset in the trie stream, iterating
|
||||
// until all uleb128 sizes have stabilized.
|
||||
bool more;
|
||||
do {
|
||||
uint32_t offset = 0;
|
||||
more = false;
|
||||
for (TrieNode* node : allNodes) {
|
||||
if (node->updateOffset(offset))
|
||||
more = true;
|
||||
}
|
||||
} while (more);
|
||||
|
||||
// Serialize trie to ByteBuffer.
|
||||
for (TrieNode* node : allNodes) {
|
||||
node->appendToByteBuffer(_exportTrie);
|
||||
}
|
||||
_exportTrie.align(_is64 ? 8 : 4);
|
||||
}
|
||||
|
||||
|
||||
void MachOFileLayout::computeSymbolTableSizes() {
|
||||
// MachO symbol tables have three ranges: locals, globals, and undefines
|
||||
const size_t nlistSize = (_is64 ? sizeof(nlist_64) : sizeof(nlist));
|
||||
|
|
@ -998,6 +1229,7 @@ void MachOFileLayout::writeLinkEditContent() {
|
|||
writeBindingInfo();
|
||||
writeLazyBindingInfo();
|
||||
// TODO: add weak binding info
|
||||
writeExportInfo();
|
||||
writeSymbolTable();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ public:
|
|||
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 addExportInfo(const lld::File &, NormalizedFile &file);
|
||||
void addSectionRelocs(const lld::File &, NormalizedFile &file);
|
||||
void buildDataInCodeArray(const lld::File &, NormalizedFile &file);
|
||||
void addDependentDylibs(const lld::File &, NormalizedFile &file);
|
||||
|
|
@ -1085,6 +1086,35 @@ void Util::addRebaseAndBindingInfo(const lld::File &atomFile,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) {
|
||||
if (_context.outputMachOType() == llvm::MachO::MH_OBJECT)
|
||||
return;
|
||||
|
||||
for (SectionInfo *sect : _sectionInfos) {
|
||||
for (const AtomInfo &info : sect->atomsAndOffsets) {
|
||||
const DefinedAtom *atom = info.atom;
|
||||
if (atom->scope() != Atom::scopeGlobal)
|
||||
continue;
|
||||
if (_context.exportRestrictMode()) {
|
||||
if (!_context.exportSymbolNamed(atom->name()))
|
||||
continue;
|
||||
}
|
||||
Export exprt;
|
||||
exprt.name = atom->name();
|
||||
exprt.offset = _atomToAddress[atom]; // FIXME: subtract base address
|
||||
exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
|
||||
if (atom->merge() == DefinedAtom::mergeAsWeak)
|
||||
exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
|
||||
else
|
||||
exprt.flags = 0;
|
||||
exprt.otherOffset = 0;
|
||||
exprt.otherName = StringRef();
|
||||
nFile.exportInfo.push_back(exprt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Util::fileFlags() {
|
||||
// FIXME: these need to determined at runtime.
|
||||
if (_context.outputMachOType() == MH_OBJECT) {
|
||||
|
|
@ -1128,6 +1158,7 @@ normalizedFromAtoms(const lld::File &atomFile,
|
|||
}
|
||||
util.addIndirectSymbols(atomFile, normFile);
|
||||
util.addRebaseAndBindingInfo(atomFile, normFile);
|
||||
util.addExportInfo(atomFile, normFile);
|
||||
util.addSectionRelocs(atomFile, normFile);
|
||||
util.buildDataInCodeArray(atomFile, normFile);
|
||||
util.copyEntryPointAddress(normFile);
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section §ion,
|
|||
bool thumb = (symbolDescFlags & N_ARM_THUMB_DEF);
|
||||
if (atomType == DefinedAtom::typeUnknown) {
|
||||
// Mach-O needs a segment and section name. Concatentate those two
|
||||
// with a / seperator (e.g. "seg/sect") to fit into the lld model
|
||||
// with a / separator (e.g. "seg/sect") to fit into the lld model
|
||||
// of just a section name.
|
||||
std::string segSectName = section.segmentName.str()
|
||||
+ "/" + section.sectionName.str();
|
||||
|
|
@ -676,10 +676,19 @@ normalizedDylibToAtoms(const NormalizedFile &normalizedFile, StringRef path,
|
|||
std::unique_ptr<MachODylibFile> file(
|
||||
new MachODylibFile(path, normalizedFile.installName));
|
||||
// Tell MachODylibFile object about all symbols it exports.
|
||||
for (auto &sym : normalizedFile.globalSymbols) {
|
||||
assert((sym.scope & N_EXT) && "only expect external symbols here");
|
||||
bool weakDef = (sym.desc & N_WEAK_DEF);
|
||||
file->addExportedSymbol(sym.name, weakDef, copyRefs);
|
||||
if (!normalizedFile.exportInfo.empty()) {
|
||||
// If exports trie exists, use it instead of traditional symbol table.
|
||||
for (const Export &exp : normalizedFile.exportInfo) {
|
||||
bool weakDef = (exp.flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
|
||||
// StringRefs from export iterator are ephemeral, so force copy.
|
||||
file->addExportedSymbol(exp.name, weakDef, true);
|
||||
}
|
||||
} else {
|
||||
for (auto &sym : normalizedFile.globalSymbols) {
|
||||
assert((sym.scope & N_EXT) && "only expect external symbols here");
|
||||
bool weakDef = (sym.desc & N_WEAK_DEF);
|
||||
file->addExportedSymbol(sym.name, weakDef, copyRefs);
|
||||
}
|
||||
}
|
||||
// Tell MachODylibFile object about all dylibs it re-exports.
|
||||
for (const DependentDylib &dep : normalizedFile.dependentDylibs) {
|
||||
|
|
|
|||
|
|
@ -566,8 +566,10 @@ struct ScalarEnumerationTraits<ExportSymbolKind> {
|
|||
static void enumeration(IO &io, ExportSymbolKind &value) {
|
||||
io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
|
||||
llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
|
||||
io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCALl",
|
||||
io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
|
||||
llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
|
||||
io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
|
||||
llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -588,11 +590,12 @@ template <>
|
|||
struct MappingTraits<Export> {
|
||||
static void mapping(IO &io, Export &exp) {
|
||||
io.mapRequired("name", exp.name);
|
||||
io.mapRequired("offset", exp.offset);
|
||||
io.mapOptional("offset", exp.offset);
|
||||
io.mapOptional("kind", exp.kind,
|
||||
llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
|
||||
io.mapOptional("flags", exp.flags);
|
||||
io.mapOptional("other-offset", exp.otherOffset, Hex32(0));
|
||||
if (!io.outputting() || exp.flags)
|
||||
io.mapOptional("flags", exp.flags);
|
||||
io.mapOptional("other", exp.otherOffset, Hex32(0));
|
||||
io.mapOptional("other-name", exp.otherName, StringRef());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \
|
||||
# RUN: %s %p/Inputs/libSystem.yaml -o %t && \
|
||||
# RUN: llvm-objdump -exports-trie %t | FileCheck %s
|
||||
#
|
||||
#
|
||||
# Tests that exports trie builds properly.
|
||||
#
|
||||
|
||||
--- !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: [ 0xC3, 0xC3, 0xC3 ]
|
||||
global-symbols:
|
||||
- name: _myHidden
|
||||
type: N_SECT
|
||||
scope: [ N_EXT, N_PEXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: _myRegular
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
- name: _myWeak
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
desc: [ N_WEAK_DEF ]
|
||||
value: 0x0000000000000002
|
||||
...
|
||||
|
||||
# CHECK-NOT: _myHidden
|
||||
# CHECK: _myRegular
|
||||
# CHECK: _myWeak [weak_def]
|
||||
|
|
@ -61,28 +61,10 @@ undefined-symbols:
|
|||
--- !mach-o
|
||||
arch: armv6
|
||||
file-type: MH_DYLIB
|
||||
flags: [ ]
|
||||
install-name: /usr/lib/libSystem.B.dylib
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
address: 0x0000000000000000
|
||||
content: [ 0x55 ]
|
||||
|
||||
global-symbols:
|
||||
exports:
|
||||
- name: _printf
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
- name: dyld_stub_binder
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
|
||||
...
|
||||
|
||||
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external _main
|
||||
|
|
|
|||
|
|
@ -74,28 +74,10 @@ undefined-symbols:
|
|||
--- !mach-o
|
||||
arch: armv7
|
||||
file-type: MH_DYLIB
|
||||
flags: [ ]
|
||||
install-name: /usr/lib/libSystem.B.dylib
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
address: 0x0000000000000000
|
||||
content: [ 0x55 ]
|
||||
|
||||
global-symbols:
|
||||
exports:
|
||||
- name: _printf
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
- name: dyld_stub_binder
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
|
||||
...
|
||||
|
||||
# CHECK: {{[0-9a-f]+}} (__TEXT,__text) external [Thumb] _main
|
||||
|
|
|
|||
|
|
@ -59,27 +59,10 @@ undefined-symbols:
|
|||
--- !mach-o
|
||||
arch: x86
|
||||
file-type: MH_DYLIB
|
||||
flags: [ ]
|
||||
install-name: /usr/lib/libSystem.B.dylib
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
address: 0x0000000000000000
|
||||
content: [ 0x55 ]
|
||||
|
||||
global-symbols:
|
||||
exports:
|
||||
- name: _printf
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
- name: dyld_stub_binder
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000001
|
||||
|
||||
...
|
||||
|
||||
|
|
|
|||
|
|
@ -112,32 +112,11 @@ undefined-symbols:
|
|||
--- !mach-o
|
||||
arch: x86_64
|
||||
file-type: MH_DYLIB
|
||||
flags: [ ]
|
||||
install-name: /usr/lib/libSystem.B.dylib
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
address: 0x0000000000000000
|
||||
content: [ 0x55 ]
|
||||
|
||||
global-symbols:
|
||||
exports:
|
||||
- name: _fprintf
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: dyld_stub_binder
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: ___stdoutp
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
|
||||
...
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue