[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:
Nick Kledzik 2014-09-03 19:52:50 +00:00
parent ed9709d928
commit 141330aef6
10 changed files with 362 additions and 92 deletions

View File

@ -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) {}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -235,7 +235,7 @@ void atomFromSymbol(DefinedAtom::ContentType atomType, const Section &section,
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) {

View File

@ -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());
}
};

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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
...

View File

@ -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
...