aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/MachOObjectFile.cpp
diff options
context:
space:
mode:
authorDaniel Bertalan <dani@danielbertalan.dev>2022-08-16 17:14:27 +0200
committerDaniel Bertalan <dani@danielbertalan.dev>2022-08-24 19:29:11 +0200
commit686d8ce1ab16171c66973e065eada5b6419a0c98 (patch)
treeb7bc0d8d00de8840d1ac35ddc836c4c74e4d979d /llvm/lib/Object/MachOObjectFile.cpp
parent096463d08eaa053c000700c3d4648f0c93cb7af6 (diff)
downloadllvm-686d8ce1ab16171c66973e065eada5b6419a0c98.zip
llvm-686d8ce1ab16171c66973e065eada5b6419a0c98.tar.gz
llvm-686d8ce1ab16171c66973e065eada5b6419a0c98.tar.bz2
[llvm-objdump] Complete -chained_fixups support
This commit adds definitions for the `dyld_chained_import*` structs. The imports array is now printed with `llvm-otool -chained_fixups`. This completes this option's implementation. A slight difference from cctools otool is that we don't yet dump the raw bytes of the imports entries. 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/D131982
Diffstat (limited to 'llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp112
1 files changed, 110 insertions, 2 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index d7e9b57..0c202b2 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/bit.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/Swift.h"
#include "llvm/Object/Error.h"
@@ -4924,15 +4925,122 @@ MachOObjectFile::getChainedFixupsSegments() const {
return std::make_pair(ImageStarts.seg_count, Segments);
}
+// The special library ordinals have a negative value, but they are encoded in
+// an unsigned bitfield, so we need to sign extend the value.
+template <typename T> static int getEncodedOrdinal(T Value) {
+ if (Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE) ||
+ Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) ||
+ Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP))
+ return SignExtend32<sizeof(T) * CHAR_BIT>(Value);
+ return Value;
+}
+
+template <typename T, unsigned N>
+static std::array<T, N> getArray(const MachOObjectFile &O, const void *Ptr) {
+ std::array<T, N> RawValue;
+ memcpy(RawValue.data(), Ptr, N * sizeof(T));
+ if (O.isLittleEndian() != sys::IsLittleEndianHost)
+ for (auto &Element : RawValue)
+ sys::swapByteOrder(Element);
+ return RawValue;
+}
+
Expected<std::vector<ChainedFixupTarget>>
MachOObjectFile::getDyldChainedFixupTargets() const {
+ auto CFOrErr = getChainedFixupsLoadCommand();
+ if (!CFOrErr)
+ return CFOrErr.takeError();
+
+ std::vector<ChainedFixupTarget> Targets;
+ if (!CFOrErr->has_value())
+ return Targets;
+
+ const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
+
auto CFHeaderOrErr = getChainedFixupsHeader();
if (!CFHeaderOrErr)
return CFHeaderOrErr.takeError();
- std::vector<ChainedFixupTarget> Targets;
if (!(*CFHeaderOrErr))
return Targets;
- return Targets;
+ const MachO::dyld_chained_fixups_header &Header = **CFHeaderOrErr;
+
+ size_t ImportSize = 0;
+ if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT)
+ ImportSize = sizeof(MachO::dyld_chained_import);
+ else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND)
+ ImportSize = sizeof(MachO::dyld_chained_import_addend);
+ else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64)
+ ImportSize = sizeof(MachO::dyld_chained_import_addend64);
+ else
+ return malformedError("bad chained fixups: unknown imports format: " +
+ Twine(Header.imports_format));
+
+ const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);
+ const char *Imports = Contents + Header.imports_offset;
+ size_t ImportsEndOffset =
+ Header.imports_offset + ImportSize * Header.imports_count;
+ const char *ImportsEnd = Contents + ImportsEndOffset;
+ const char *Symbols = Contents + Header.symbols_offset;
+ const char *SymbolsEnd = Contents + DyldChainedFixups.datasize;
+
+ if (ImportsEnd > Symbols)
+ return malformedError("bad chained fixups: imports end " +
+ Twine(ImportsEndOffset) + " extends past end " +
+ Twine(DyldChainedFixups.datasize));
+
+ if (ImportsEnd > Symbols)
+ return malformedError("bad chained fixups: imports end " +
+ Twine(ImportsEndOffset) + " overlaps with symbols");
+
+ // We use bit manipulation to extract data from the bitfields. This is correct
+ // for both LE and BE hosts, but we assume that the object is little-endian.
+ if (!isLittleEndian())
+ return createError("parsing big-endian chained fixups is not implemented");
+ for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd;
+ ImportPtr += ImportSize) {
+ int LibOrdinal;
+ bool WeakImport;
+ uint32_t NameOffset;
+ uint64_t Addend;
+ if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) {
+ static_assert(sizeof(uint32_t) == sizeof(MachO::dyld_chained_import));
+ auto RawValue = getArray<uint32_t, 1>(*this, ImportPtr);
+
+ LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);
+ WeakImport = (RawValue[0] >> 8) & 1;
+ NameOffset = RawValue[0] >> 9;
+ Addend = 0;
+ } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) {
+ static_assert(sizeof(uint64_t) ==
+ sizeof(MachO::dyld_chained_import_addend));
+ auto RawValue = getArray<uint32_t, 2>(*this, ImportPtr);
+
+ LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF);
+ WeakImport = (RawValue[0] >> 8) & 1;
+ NameOffset = RawValue[0] >> 9;
+ Addend = bit_cast<int32_t>(RawValue[1]);
+ } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) {
+ static_assert(2 * sizeof(uint64_t) ==
+ sizeof(MachO::dyld_chained_import_addend64));
+ auto RawValue = getArray<uint64_t, 2>(*this, ImportPtr);
+
+ LibOrdinal = getEncodedOrdinal<uint16_t>(RawValue[0] & 0xFFFF);
+ NameOffset = (RawValue[0] >> 16) & 1;
+ WeakImport = RawValue[0] >> 17;
+ Addend = RawValue[1];
+ } else {
+ llvm_unreachable("Import format should have been checked");
+ }
+
+ const char *Str = Symbols + NameOffset;
+ if (Str >= SymbolsEnd)
+ return malformedError("bad chained fixups: symbol offset " +
+ Twine(NameOffset) + " extends past end " +
+ Twine(DyldChainedFixups.datasize));
+ Targets.emplace_back(LibOrdinal, NameOffset, Str, Addend, WeakImport);
+ }
+
+ return std::move(Targets);
}
ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {