diff options
author | Adrian Prantl <aprantl@apple.com> | 2021-11-10 16:25:26 -0800 |
---|---|---|
committer | Adrian Prantl <aprantl@apple.com> | 2022-02-22 11:06:27 -0800 |
commit | a3bfb01d94cc486280f2f13f5e86f4070bf3b450 (patch) | |
tree | d32d25afc2752ab4dcc4e4d2c6d261705bc1ff76 /llvm/lib/Object/MachOObjectFile.cpp | |
parent | 621e2de138f70e175512c18d9f358666de93e838 (diff) | |
download | llvm-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.cpp | 161 |
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; |