aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
authorAdrian Prantl <aprantl@apple.com>2021-11-10 16:25:26 -0800
committerAdrian Prantl <aprantl@apple.com>2022-02-22 11:06:27 -0800
commita3bfb01d94cc486280f2f13f5e86f4070bf3b450 (patch)
treed32d25afc2752ab4dcc4e4d2c6d261705bc1ff76 /llvm/lib/Object/MachOObjectFile.cpp
parent621e2de138f70e175512c18d9f358666de93e838 (diff)
downloadllvm-a3bfb01d94cc486280f2f13f5e86f4070bf3b450.zip
llvm-a3bfb01d94cc486280f2f13f5e86f4070bf3b450.tar.gz
llvm-a3bfb01d94cc486280f2f13f5e86f4070bf3b450.tar.bz2
Add support for chained fixup load commands to MachOObjectFile
This is part of a series of patches to upstream support for Mach-O chained fixups. This patch adds support for parsing the chained fixup load command and parsing the chained fixups header. It also puts into place the abstract interface that will be used to iterate over the fixups. Differential Revision: https://reviews.llvm.org/D113630
Diffstat (limited to 'llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp161
1 files changed, 158 insertions, 3 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 85f3824..0510551 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -1380,6 +1380,11 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
"LC_DYLD_INFO_ONLY", Elements)))
return;
+ } else if (Load.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) {
+ if ((Err = checkLinkeditDataCommand(
+ *this, Load, I, &DyldChainedFixupsLoadCmd,
+ "LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups")))
+ 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 "
@@ -1595,9 +1600,9 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
return;
// Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported.
} else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) {
- if ((Err = checkTwoLevelHintsCommand(*this, Load, I,
- &TwoLevelHintsLoadCmd, Elements)))
- return;
+ if ((Err = checkTwoLevelHintsCommand(*this, Load, I,
+ &TwoLevelHintsLoadCmd, Elements)))
+ return;
} else if (Load.C.cmd == MachO::LC_IDENT) {
// Note: LC_IDENT is ignored.
continue;
@@ -3185,6 +3190,106 @@ iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {
return exports(Err, getDyldInfoExportsTrie(), this);
}
+MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E,
+ const MachOObjectFile *O)
+ : E(E), O(O) {
+ // Cache the vmaddress of __TEXT
+ for (const auto &Command : O->load_commands()) {
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
+ if (StringRef(SLC.segname) == StringRef("__TEXT")) {
+ TextAddress = SLC.vmaddr;
+ break;
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(Command);
+ if (StringRef(SLC_64.segname) == StringRef("__TEXT")) {
+ TextAddress = SLC_64.vmaddr;
+ break;
+ }
+ }
+ }
+}
+
+int32_t MachOAbstractFixupEntry::segmentIndex() const { return SegmentIndex; }
+
+uint64_t MachOAbstractFixupEntry::segmentOffset() const {
+ return SegmentOffset;
+}
+
+uint64_t MachOAbstractFixupEntry::segmentAddress() const {
+ return O->BindRebaseAddress(SegmentIndex, 0);
+}
+
+StringRef MachOAbstractFixupEntry::segmentName() const {
+ return O->BindRebaseSegmentName(SegmentIndex);
+}
+
+StringRef MachOAbstractFixupEntry::sectionName() const {
+ return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
+}
+
+uint64_t MachOAbstractFixupEntry::address() const {
+ return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
+}
+
+StringRef MachOAbstractFixupEntry::symbolName() const { return SymbolName; }
+
+int64_t MachOAbstractFixupEntry::addend() const { return Addend; }
+
+uint32_t MachOAbstractFixupEntry::flags() const { return Flags; }
+
+int MachOAbstractFixupEntry::ordinal() const { return Ordinal; }
+
+StringRef MachOAbstractFixupEntry::typeName() const { return "unknown"; }
+
+void MachOAbstractFixupEntry::moveToFirst() {
+ SegmentOffset = 0;
+ SegmentIndex = -1;
+ Ordinal = 0;
+ Flags = 0;
+ Addend = 0;
+ Done = false;
+}
+
+void MachOAbstractFixupEntry::moveToEnd() { Done = true; }
+
+MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
+ const MachOObjectFile *O,
+ FixupKind Kind, bool Parse)
+ : MachOAbstractFixupEntry(E, O), Kind(Kind) {
+ ErrorAsOutParameter e(E);
+ if (Parse) {
+ if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets())
+ FixupTargets = *FixupTargetsOrErr;
+ else {
+ *E = FixupTargetsOrErr.takeError();
+ return;
+ }
+ }
+}
+
+void MachOChainedFixupEntry::moveToFirst() {
+ MachOAbstractFixupEntry::moveToFirst();
+ FixupIndex = 0;
+ moveNext();
+}
+
+void MachOChainedFixupEntry::moveToEnd() {
+ MachOAbstractFixupEntry::moveToEnd();
+}
+
+void MachOChainedFixupEntry::moveNext() { Done = true; }
+
+bool MachOChainedFixupEntry::operator==(
+ const MachOChainedFixupEntry &Other) const {
+ if (Done == Other.Done)
+ return true;
+ if ((FixupIndex == Other.FixupIndex))
+ return true;
+ return false;
+}
+
MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
ArrayRef<uint8_t> Bytes, bool is64Bit)
: E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
@@ -4193,6 +4298,18 @@ iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {
MachOBindEntry::Kind::Weak);
}
+iterator_range<fixup_iterator>
+MachOObjectFile::fixupTable(Error &Err,
+ MachOChainedFixupEntry::FixupKind Kind) {
+ MachOChainedFixupEntry Start(&Err, this, Kind, true);
+ Start.moveToFirst();
+
+ MachOChainedFixupEntry Finish(&Err, this, Kind, false);
+ Finish.moveToEnd();
+
+ return make_range(fixup_iterator(Start), fixup_iterator(Finish));
+}
+
MachOObjectFile::load_command_iterator
MachOObjectFile::begin_load_commands() const {
return LoadCommands.begin();
@@ -4648,6 +4765,44 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
}
+Expected<std::vector<ChainedFixupTarget>>
+MachOObjectFile::getDyldChainedFixupTargets() const {
+ // Load the dyld chained fixups load command.
+ if (!DyldChainedFixupsLoadCmd)
+ return std::vector<ChainedFixupTarget>();
+ auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>(
+ *this, DyldChainedFixupsLoadCmd);
+ if (!DyldChainedFixupsOrErr)
+ return DyldChainedFixupsOrErr.takeError();
+ MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get();
+
+ // If the load command is present but the data offset has been zeroed out,
+ // as is the case for dylib stubs, return an empty list of targets.
+ uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;
+ std::vector<ChainedFixupTarget> Targets;
+ if (CFHeaderOffset == 0)
+ return Targets;
+
+ // Load the dyld chained fixups header.
+ const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
+ auto CFHeaderOrErr =
+ getStructOrErr<MachO::dyld_chained_fixups_header>(*this, CFHeaderPtr);
+ if (!CFHeaderOrErr)
+ return CFHeaderOrErr.takeError();
+ MachO::dyld_chained_fixups_header CFHeader = CFHeaderOrErr.get();
+
+ // Reject unknown chained fixup formats.
+ if (CFHeader.fixups_version != 0)
+ return malformedError(Twine("bad chained fixups: unknown version: ") +
+ Twine(CFHeader.fixups_version));
+ if (CFHeader.imports_format < 1 || CFHeader.imports_format > 3)
+ return malformedError(
+ Twine("bad chained fixups: unknown imports format: ") +
+ Twine(CFHeader.imports_format));
+
+ return Targets;
+}
+
ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
if (!DyldInfoLoadCmd)
return None;