Skip to content

Commit

Permalink
[MachO] Support exports trie in both LC_DYLD_INFO and LC_DYLD_EXPORTS…
Browse files Browse the repository at this point in the history
…_TRIE

The exports trie used to be pointed by the information in LC_DYLD_INFO,
but when chained fixups are present, the exports trie is pointed by
LC_DYLD_EXPORTS_TRIE instead.

Modify the Object library to give access to the information pointed by
each of the load commands, and to fallback from one into the other when
the exports are requested.

Modify ObjectYAML to support dumping the export trie when pointed by
LC_DYLD_EXPORTS_TRIE and to parse the existence of a export trie also
when the load command is present.

This is a split of D134250 with improvements on top.

Reviewed By: alexander-shaposhnikov

Differential Revision: https://reviews.llvm.org/D134571
  • Loading branch information
drodriguez committed Nov 23, 2022
1 parent 7218103 commit 42ad9bf
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 10 deletions.
5 changes: 4 additions & 1 deletion llvm/include/llvm/Object/MachO.h
Expand Up @@ -711,6 +711,8 @@ class MachOObjectFile : public ObjectFile {
ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
ArrayRef<uint8_t> getDyldInfoExportsTrie() const;

/// If the optional is None, no header was found, but the object was
/// well-formed.
Expected<Optional<MachO::dyld_chained_fixups_header>>
Expand All @@ -725,8 +727,8 @@ class MachOObjectFile : public ObjectFile {
// a ChainedFixupsSegment for each segment that has fixups.
Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>>
getChainedFixupsSegments() const;
ArrayRef<uint8_t> getDyldExportsTrie() const;

ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
SmallVector<uint64_t> getFunctionStarts() const;
ArrayRef<uint8_t> getUuid() const;

Expand Down Expand Up @@ -856,6 +858,7 @@ class MachOObjectFile : public ObjectFile {
const char *DyldInfoLoadCmd = nullptr;
const char *FuncStartsLoadCmd = nullptr;
const char *DyldChainedFixupsLoadCmd = nullptr;
const char *DyldExportsTrieLoadCmd = nullptr;
const char *UuidLoadCmd = nullptr;
bool HasPageZeroSegment = false;
};
Expand Down
43 changes: 34 additions & 9 deletions llvm/lib/Object/MachOObjectFile.cpp
Expand Up @@ -1386,6 +1386,11 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
*this, Load, I, &DyldChainedFixupsLoadCmd,
"LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups")))
return;
} else if (Load.C.cmd == MachO::LC_DYLD_EXPORTS_TRIE) {
if ((Err = checkLinkeditDataCommand(
*this, Load, I, &DyldExportsTrieLoadCmd, "LC_DYLD_EXPORTS_TRIE",
Elements, "exports trie")))
return;
} else if (Load.C.cmd == MachO::LC_UUID) {
if (Load.C.cmdsize != sizeof(MachO::uuid_command)) {
Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect "
Expand Down Expand Up @@ -3225,7 +3230,13 @@ MachOObjectFile::exports(Error &E, ArrayRef<uint8_t> Trie,
}

iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {
return exports(Err, getDyldInfoExportsTrie(), this);
ArrayRef<uint8_t> Trie;
if (DyldInfoLoadCmd)
Trie = getDyldInfoExportsTrie();
else if (DyldExportsTrieLoadCmd)
Trie = getDyldExportsTrie();

return exports(Err, Trie, this);
}

MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E,
Expand Down Expand Up @@ -4932,6 +4943,20 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
}

ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
if (!DyldInfoLoadCmd)
return None;

auto DyldInfoOrErr =
getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
if (!DyldInfoOrErr)
return None;
MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
const uint8_t *Ptr =
reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));
return makeArrayRef(Ptr, DyldInfo.export_size);
}

Expected<Optional<MachO::linkedit_data_command>>
MachOObjectFile::getChainedFixupsLoadCommand() const {
// Load the dyld chained fixups load command.
Expand Down Expand Up @@ -5209,18 +5234,18 @@ MachOObjectFile::getDyldChainedFixupTargets() const {
return std::move(Targets);
}

ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
if (!DyldInfoLoadCmd)
ArrayRef<uint8_t> MachOObjectFile::getDyldExportsTrie() const {
if (!DyldExportsTrieLoadCmd)
return None;

auto DyldInfoOrErr =
getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
if (!DyldInfoOrErr)
auto DyldExportsTrieOrError = getStructOrErr<MachO::linkedit_data_command>(
*this, DyldExportsTrieLoadCmd);
if (!DyldExportsTrieOrError)
return None;
MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
MachO::linkedit_data_command DyldExportsTrie = DyldExportsTrieOrError.get();
const uint8_t *Ptr =
reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));
return makeArrayRef(Ptr, DyldInfo.export_size);
reinterpret_cast<const uint8_t *>(getPtr(*this, DyldExportsTrie.dataoff));
return makeArrayRef(Ptr, DyldExportsTrie.datasize);
}

SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const {
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/ObjectYAML/MachOEmitter.cpp
Expand Up @@ -57,6 +57,7 @@ class MachOWriter {
void writeDynamicSymbolTable(raw_ostream &OS);
void writeFunctionStarts(raw_ostream &OS);
void writeChainedFixups(raw_ostream &OS);
void writeDyldExportsTrie(raw_ostream &OS);
void writeDataInCode(raw_ostream &OS);

void dumpExportEntry(raw_ostream &OS, MachOYAML::ExportEntry &Entry);
Expand Down Expand Up @@ -489,6 +490,7 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) {
MachO::dysymtab_command *DSymtabCmd = nullptr;
MachO::linkedit_data_command *FunctionStartsCmd = nullptr;
MachO::linkedit_data_command *ChainedFixupsCmd = nullptr;
MachO::linkedit_data_command *DyldExportsTrieCmd = nullptr;
MachO::linkedit_data_command *DataInCodeCmd = nullptr;
for (auto &LC : Obj.LoadCommands) {
switch (LC.Data.load_command_data.cmd) {
Expand Down Expand Up @@ -527,6 +529,11 @@ void MachOWriter::writeLinkEditData(raw_ostream &OS) {
WriteQueue.push_back(std::make_pair(ChainedFixupsCmd->dataoff,
&MachOWriter::writeChainedFixups));
break;
case MachO::LC_DYLD_EXPORTS_TRIE:
DyldExportsTrieCmd = &LC.Data.linkedit_data_command_data;
WriteQueue.push_back(std::make_pair(DyldExportsTrieCmd->dataoff,
&MachOWriter::writeDyldExportsTrie));
break;
case MachO::LC_DATA_IN_CODE:
DataInCodeCmd = &LC.Data.linkedit_data_command_data;
WriteQueue.push_back(std::make_pair(DataInCodeCmd->dataoff,
Expand Down Expand Up @@ -615,6 +622,10 @@ void MachOWriter::writeChainedFixups(raw_ostream &OS) {
Obj.LinkEdit.ChainedFixups.size());
}

void MachOWriter::writeDyldExportsTrie(raw_ostream &OS) {
dumpExportEntry(OS, Obj.LinkEdit.ExportTrie);
}

class UniversalWriter {
public:
UniversalWriter(yaml::YamlObjectFile &ObjectFile)
Expand Down
204 changes: 204 additions & 0 deletions llvm/test/ObjectYAML/MachO/export_trie_lc_dyld_exports_trie.yaml
@@ -0,0 +1,204 @@
# RUN: yaml2obj %s -o=%t
# RUN: obj2yaml %t | FileCheck %s
# RUN: llvm-objdump --macho --exports-trie %t | FileCheck %s --check-prefix=OBJDUMP-VERIFY

--- !mach-o
FileHeader:
magic: 0xFEEDFACF
cputype: 0x01000007
cpusubtype: 0x80000003
filetype: 0x00000002
ncmds: 16
sizeofcmds: 1408
flags: 0x00218085
reserved: 0x00000000
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 72
segname: __PAGEZERO
vmaddr: 0
vmsize: 4294967296
fileoff: 0
filesize: 0
maxprot: 0
initprot: 0
nsects: 0
flags: 0
- cmd: LC_SEGMENT_64
cmdsize: 552
segname: __TEXT
vmaddr: 4294967296
vmsize: 8192
fileoff: 0
filesize: 8192
maxprot: 7
initprot: 5
nsects: 6
flags: 0
- cmd: LC_SEGMENT_64
cmdsize: 312
segname: __DATA
vmaddr: 4294975488
vmsize: 4096
fileoff: 8192
filesize: 4096
maxprot: 7
initprot: 3
nsects: 3
flags: 0
- cmd: LC_SEGMENT_64
cmdsize: 72
segname: __LINKEDIT
vmaddr: 4294979584
vmsize: 4096
fileoff: 12288
filesize: 1884
maxprot: 7
initprot: 1
nsects: 0
flags: 0
- cmd: LC_DYLD_CHAINED_FIXUPS
cmdsize: 16
dataoff: 12288
datasize: 104
- cmd: LC_DYLD_EXPORTS_TRIE
cmdsize: 16
dataoff: 12392
datasize: 48
- cmd: LC_SYMTAB
cmdsize: 24
symoff: 12456
nsyms: 30
stroff: 13076
strsize: 1096
- cmd: LC_DYSYMTAB
cmdsize: 80
ilocalsym: 0
nlocalsym: 9
iextdefsym: 9
nextdefsym: 2
iundefsym: 11
nundefsym: 19
tocoff: 0
ntoc: 0
modtaboff: 0
nmodtab: 0
extrefsymoff: 0
nextrefsyms: 0
indirectsymoff: 12936
nindirectsyms: 35
extreloff: 0
nextrel: 0
locreloff: 0
nlocrel: 0
- cmd: LC_LOAD_DYLINKER
cmdsize: 32
name: 12
Content: /usr/lib/dyld
ZeroPadBytes: 7
- cmd: LC_UUID
cmdsize: 24
uuid: 461A1B28-822F-3F38-B670-645419E636F5
- cmd: LC_VERSION_MIN_MACOSX
cmdsize: 16
version: 658176
sdk: 658176
- cmd: LC_SOURCE_VERSION
cmdsize: 16
version: 0
- cmd: LC_MAIN
cmdsize: 24
entryoff: 4448
stacksize: 0
- cmd: LC_LOAD_DYLIB
cmdsize: 48
dylib:
name: 24
timestamp: 2
current_version: 7864576
compatibility_version: 65536
Content: '/usr/lib/libc++.1.dylib'
ZeroPadBytes: 1
- cmd: LC_LOAD_DYLIB
cmdsize: 56
dylib:
name: 24
timestamp: 2
current_version: 80349697
compatibility_version: 65536
Content: /usr/lib/libSystem.B.dylib
ZeroPadBytes: 6
- cmd: LC_FUNCTION_STARTS
cmdsize: 16
dataoff: 12440
datasize: 16
- cmd: LC_DATA_IN_CODE
cmdsize: 16
dataoff: 12456
datasize: 0
LinkEditData:
ExportTrie:
TerminalSize: 0
NodeOffset: 0
Name: ''
Flags: 0x0000000000000000
Address: 0x0000000000000000
Other: 0x0000000000000000
ImportName: ''
Children:
- TerminalSize: 0
NodeOffset: 5
Name: _
Flags: 0x0000000000000000
Address: 0x0000000000000000
Other: 0x0000000000000000
ImportName: ''
Children:
- TerminalSize: 2
NodeOffset: 33
Name: _mh_execute_header
Flags: 0x0000000000000000
Address: 0x0000000000000000
Other: 0x0000000000000000
ImportName: ''
- TerminalSize: 3
NodeOffset: 37
Name: main
Flags: 0x0000000000000000
Address: 0x0000000000003FA0
Other: 0x0000000000000000
ImportName: ''
ChainedFixups: [ 0x0, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x50, 0x0,
0x0, 0x0, 0x58, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0,
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x18, 0x0, 0x0, 0x0,
0x0, 0x10, 0x6, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
0x1, 0x2, 0x0, 0x0, 0xFD, 0xC, 0x0, 0x0, 0x0, 0x5F,
0x66, 0x6F, 0x6F, 0x0, 0x5F, 0x77, 0x65, 0x61, 0x6B,
0x5F, 0x66, 0x6F, 0x6F, 0x0 ]
...

#CHECK: ExportTrie:
#CHECK: TerminalSize: 0
#CHECK: NodeOffset: 0
#CHECK: Name: ''
#CHECK: Children:
#CHECK: - TerminalSize: 0
#CHECK: NodeOffset: 5
#CHECK: Name: _
#CHECK: Children:
#CHECK: - TerminalSize: 2
#CHECK: NodeOffset: 33
#CHECK: Name: _mh_execute_header
#CHECK: Address: 0x0
#CHECK: - TerminalSize: 3
#CHECK: NodeOffset: 37
#CHECK: Name: main
#CHECK: Address: 0x3FA0

# OBJDUMP-VERIFY: Exports trie:
# OBJDUMP-VERIFY: 0x100000000 __mh_execute_header
# OBJDUMP-VERIFY: 0x100003FA0 _main
File renamed without changes.
3 changes: 3 additions & 0 deletions llvm/tools/obj2yaml/macho2yaml.cpp
Expand Up @@ -580,7 +580,10 @@ const uint8_t *processExportNode(const uint8_t *CurrPtr,

void MachODumper::dumpExportTrie(std::unique_ptr<MachOYAML::Object> &Y) {
MachOYAML::LinkEditData &LEData = Y->LinkEdit;
// The exports trie can be in LC_DYLD_INFO or LC_DYLD_EXPORTS_TRIE
auto ExportsTrie = Obj.getDyldInfoExportsTrie();
if (ExportsTrie.empty())
ExportsTrie = Obj.getDyldExportsTrie();
processExportNode(ExportsTrie.begin(), ExportsTrie.end(), LEData.ExportTrie);
}

Expand Down

0 comments on commit 42ad9bf

Please sign in to comment.