aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2022-08-17 16:14:03 +0200
committerDaniel Bertalan <dani@danielbertalan.dev>2022-08-28 09:22:41 +0200
commit47e4663c4eacaedab63e407651f5b045446bb36d (patch)
tree2f6a9e1483d4de9f2c11cfd014e2df91659a5d7e /llvm/lib/Object/MachOObjectFile.cpp
parentf4feb7dd6ae42e3a50cbe25a71c7f69f1f1acb69 (diff)
downloadllvm-47e4663c4eacaedab63e407651f5b045446bb36d.zip
llvm-47e4663c4eacaedab63e407651f5b045446bb36d.tar.gz
llvm-47e4663c4eacaedab63e407651f5b045446bb36d.tar.bz2
[llvm-objdump] Add -dyld_info to llvm-otool
This option outputs the location, encoded value and target of chained fixups, using the same format as `otool -dyld_info`. This initial implementation only supports the DYLD_CHAINED_PTR_64 and DYLD_CHAINED_PTR_64_OFFSET pointer encodings, which are used in x86_64 and arm64 userspace binaries. When Apple's effort to upstream their chained fixups code continues, we'll replace this code with the then-upstreamed code. But we need something in the meantime for testing ld64.lld's chained fixups code. Differential Revision: https://reviews.llvm.org/D132036
Diffstat (limited to 'llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp186
1 files changed, 176 insertions, 10 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 0c202b2..0b06ec3 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -2073,6 +2073,19 @@ ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,
Segment.fileoff, Segment.fileoff + Segment.filesize));
return {};
}
+
+template <typename LoadCommandType>
+ArrayRef<uint8_t> getSegmentContents(const MachOObjectFile &Obj,
+ MachOObjectFile::LoadCommandInfo LoadCmd) {
+ auto SegmentOrErr = getStructOrErr<LoadCommandType>(Obj, LoadCmd.Ptr);
+ if (!SegmentOrErr) {
+ consumeError(SegmentOrErr.takeError());
+ return {};
+ }
+ auto &Segment = SegmentOrErr.get();
+ return arrayRefFromStringRef(
+ Obj.getData().slice(Segment.fileoff, Segment.fileoff + Segment.filesize));
+}
} // namespace
ArrayRef<uint8_t>
@@ -2097,6 +2110,28 @@ MachOObjectFile::getSegmentContents(StringRef SegmentName) const {
return {};
}
+ArrayRef<uint8_t>
+MachOObjectFile::getSegmentContents(size_t SegmentIndex) const {
+ size_t Idx = 0;
+ for (auto LoadCmd : load_commands()) {
+ switch (LoadCmd.C.cmd) {
+ case MachO::LC_SEGMENT:
+ if (Idx == SegmentIndex)
+ return ::getSegmentContents<MachO::segment_command>(*this, LoadCmd);
+ ++Idx;
+ break;
+ case MachO::LC_SEGMENT_64:
+ if (Idx == SegmentIndex)
+ return ::getSegmentContents<MachO::segment_command_64>(*this, LoadCmd);
+ ++Idx;
+ break;
+ default:
+ continue;
+ }
+ }
+ return {};
+}
+
unsigned MachOObjectFile::getSectionID(SectionRef Sec) const {
return Sec.getRawDataRefImpl().d.a;
}
@@ -3257,6 +3292,8 @@ void MachOAbstractFixupEntry::moveToFirst() {
void MachOAbstractFixupEntry::moveToEnd() { Done = true; }
+void MachOAbstractFixupEntry::moveNext() {}
+
MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
const MachOObjectFile *O,
bool Parse)
@@ -3264,17 +3301,54 @@ MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
ErrorAsOutParameter e(E);
if (!Parse)
return;
- if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets())
+
+ if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) {
FixupTargets = *FixupTargetsOrErr;
- else {
+ } else {
*E = FixupTargetsOrErr.takeError();
return;
}
+
+ if (auto SegmentsOrErr = O->getChainedFixupsSegments()) {
+ Segments = std::move(SegmentsOrErr->second);
+ } else {
+ *E = SegmentsOrErr.takeError();
+ return;
+ }
+}
+
+void MachOChainedFixupEntry::findNextPageWithFixups() {
+ auto FindInSegment = [this]() {
+ const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];
+ while (PageIndex < SegInfo.PageStarts.size() &&
+ SegInfo.PageStarts[PageIndex] == MachO::DYLD_CHAINED_PTR_START_NONE)
+ ++PageIndex;
+ return PageIndex < SegInfo.PageStarts.size();
+ };
+
+ while (InfoSegIndex < Segments.size()) {
+ if (FindInSegment()) {
+ PageOffset = Segments[InfoSegIndex].PageStarts[PageIndex];
+ SegmentData = O->getSegmentContents(Segments[InfoSegIndex].SegIdx);
+ return;
+ }
+
+ InfoSegIndex++;
+ PageIndex = 0;
+ }
}
void MachOChainedFixupEntry::moveToFirst() {
MachOAbstractFixupEntry::moveToFirst();
- FixupIndex = 0;
+ if (Segments.empty()) {
+ Done = true;
+ return;
+ }
+
+ InfoSegIndex = 0;
+ PageIndex = 0;
+
+ findNextPageWithFixups();
moveNext();
}
@@ -3282,15 +3356,104 @@ void MachOChainedFixupEntry::moveToEnd() {
MachOAbstractFixupEntry::moveToEnd();
}
-void MachOChainedFixupEntry::moveNext() { Done = true; }
+void MachOChainedFixupEntry::moveNext() {
+ ErrorAsOutParameter ErrAsOutParam(E);
+
+ if (InfoSegIndex == Segments.size()) {
+ Done = true;
+ return;
+ }
+
+ const ChainedFixupsSegment &SegInfo = Segments[InfoSegIndex];
+ SegmentIndex = SegInfo.SegIdx;
+ SegmentOffset = SegInfo.Header.page_size * PageIndex + PageOffset;
+
+ // FIXME: Handle other pointer formats.
+ uint16_t PointerFormat = SegInfo.Header.pointer_format;
+ if (PointerFormat != MachO::DYLD_CHAINED_PTR_64 &&
+ PointerFormat != MachO::DYLD_CHAINED_PTR_64_OFFSET) {
+ *E = createError("segment " + Twine(SegmentIndex) +
+ " has unsupported chained fixup pointer_format " +
+ Twine(PointerFormat));
+ moveToEnd();
+ return;
+ }
+
+ Ordinal = 0;
+ Flags = 0;
+ Addend = 0;
+ PointerValue = 0;
+ SymbolName = {};
+
+ if (SegmentOffset + sizeof(RawValue) > SegmentData.size()) {
+ *E = malformedError("fixup in segment " + Twine(SegmentIndex) +
+ " at offset " + Twine(SegmentOffset) +
+ " extends past segment's end");
+ moveToEnd();
+ return;
+ }
+
+ static_assert(sizeof(RawValue) == sizeof(MachO::dyld_chained_import_addend));
+ memcpy(&RawValue, SegmentData.data() + SegmentOffset, sizeof(RawValue));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(RawValue);
+
+ // The bit extraction below assumes little-endian fixup entries.
+ assert(O->isLittleEndian() && "big-endian object should have been rejected "
+ "by getDyldChainedFixupTargets()");
+ auto Field = [this](uint8_t Right, uint8_t Count) {
+ return (RawValue >> Right) & ((1ULL << Count) - 1);
+ };
+
+ // The `bind` field (most significant bit) of the encoded fixup determines
+ // whether it is dyld_chained_ptr_64_bind or dyld_chained_ptr_64_rebase.
+ bool IsBind = Field(63, 1);
+ Kind = IsBind ? FixupKind::Bind : FixupKind::Rebase;
+ uint32_t Next = Field(51, 12);
+ if (IsBind) {
+ uint32_t ImportOrdinal = Field(0, 24);
+ uint8_t InlineAddend = Field(24, 8);
+
+ if (ImportOrdinal >= FixupTargets.size()) {
+ *E = malformedError("fixup in segment " + Twine(SegmentIndex) +
+ " at offset " + Twine(SegmentOffset) +
+ " has out-of range import ordinal " +
+ Twine(ImportOrdinal));
+ moveToEnd();
+ return;
+ }
+
+ ChainedFixupTarget &Target = FixupTargets[ImportOrdinal];
+ Ordinal = Target.libOrdinal();
+ Addend = InlineAddend ? InlineAddend : Target.addend();
+ Flags = Target.weakImport() ? MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT : 0;
+ SymbolName = Target.symbolName();
+ } else {
+ uint64_t Target = Field(0, 36);
+ uint64_t High8 = Field(36, 8);
+
+ PointerValue = Target | (High8 << 56);
+ if (PointerFormat == MachO::DYLD_CHAINED_PTR_64_OFFSET)
+ PointerValue += textAddress();
+ }
+
+ // The stride is 4 bytes for DYLD_CHAINED_PTR_64(_OFFSET).
+ if (Next != 0) {
+ PageOffset += 4 * Next;
+ } else {
+ ++PageIndex;
+ findNextPageWithFixups();
+ }
+}
bool MachOChainedFixupEntry::operator==(
const MachOChainedFixupEntry &Other) const {
- if (Done == Other.Done)
- return true;
- if ((FixupIndex == Other.FixupIndex))
+ if (Done && Other.Done)
return true;
- return false;
+ if (Done != Other.Done)
+ return false;
+ return InfoSegIndex == Other.InfoSegIndex && PageIndex == Other.PageIndex &&
+ PageOffset == Other.PageOffset;
}
MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
@@ -4302,6 +4465,9 @@ iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {
}
iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) {
+ if (BindRebaseSectionTable == nullptr)
+ BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(this);
+
MachOChainedFixupEntry Start(&Err, this, true);
Start.moveToFirst();
@@ -4836,13 +5002,13 @@ MachOObjectFile::getChainedFixupsHeader() const {
return CFHeader;
}
-Expected<std::pair<size_t, std::vector<MachOObjectFile::ChainedFixupsSegment>>>
+Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>>
MachOObjectFile::getChainedFixupsSegments() const {
auto CFOrErr = getChainedFixupsLoadCommand();
if (!CFOrErr)
return CFOrErr.takeError();
- std::vector<MachOObjectFile::ChainedFixupsSegment> Segments;
+ std::vector<ChainedFixupsSegment> Segments;
if (!CFOrErr->has_value())
return std::make_pair(0, Segments);