diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-04 19:20:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-08 19:02:26 +0000 |
commit | 81ad626541db97eb356e2c1d4a20eb2a26a766ab (patch) | |
tree | 311b6a8987c32b1e1dcbab65c54cfac3fdb56175 /contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp | |
parent | 5fff09660e06a66bed6482da9c70df328e16bbb6 (diff) | |
parent | 145449b1e420787bb99721a429341fa6be3adfb6 (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp | 229 |
1 files changed, 223 insertions, 6 deletions
diff --git a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp index 3d95b18f4672..2f463a1bd458 100644 --- a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp @@ -34,7 +34,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" @@ -1303,7 +1303,6 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, } const char *DyldIdLoadCmd = nullptr; - const char *FuncStartsLoadCmd = nullptr; const char *SplitInfoLoadCmd = nullptr; const char *CodeSignDrsLoadCmd = nullptr; const char *CodeSignLoadCmd = nullptr; @@ -1381,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 " @@ -1596,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; @@ -2993,7 +2997,9 @@ void ExportEntry::pushNode(uint64_t offset) { return; } if (O != nullptr) { - if (State.Other > O->getLibraryCount()) { + // Only positive numbers represent library ordinals. Zero and negative + // numbers have special meaning (see BindSpecialDylib). + if ((int64_t)State.Other > 0 && State.Other > O->getLibraryCount()) { *E = malformedError( "bad library ordinal: " + Twine((int)State.Other) + " (max " + Twine((int)O->getLibraryCount()) + @@ -3186,6 +3192,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, + bool Parse) + : MachOAbstractFixupEntry(E, O) { + ErrorAsOutParameter e(E); + if (!Parse) + return; + 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()), @@ -4194,6 +4300,16 @@ iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) { MachOBindEntry::Kind::Weak); } +iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) { + MachOChainedFixupEntry Start(&Err, this, true); + Start.moveToFirst(); + + MachOChainedFixupEntry Finish(&Err, this, false); + Finish.moveToEnd(); + + return make_range(fixup_iterator(Start), fixup_iterator(Finish)); +} + MachOObjectFile::load_command_iterator MachOObjectFile::begin_load_commands() const { return LoadCommands.begin(); @@ -4649,6 +4765,72 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } +Expected<Optional<MachO::dyld_chained_fixups_header>> +MachOObjectFile::getChainedFixupsHeader() const { + // Load the dyld chained fixups load command. + if (!DyldChainedFixupsLoadCmd) + return llvm::None; + 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 None (no error). + uint64_t CFHeaderOffset = DyldChainedFixups.dataoff; + if (CFHeaderOffset == 0) + return DyldChainedFixupsOrErr.takeError(); + + // 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)); + + // Validate the image format. + // + // Load the image starts. + uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset); + if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) { + return malformedError(Twine("bad chained fixups: image starts offset ") + + Twine(CFHeader.starts_offset) + + " overlaps with chained fixups header"); + } + uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize; + if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) > + EndOffset) { + return malformedError(Twine("bad chained fixups: image starts end ") + + Twine(CFImageStartsOffset + + sizeof(MachO::dyld_chained_starts_in_image)) + + " extends past end " + Twine(EndOffset)); + } + + return CFHeader; +} + +Expected<std::vector<ChainedFixupTarget>> +MachOObjectFile::getDyldChainedFixupTargets() const { + auto CFHeaderOrErr = getChainedFixupsHeader(); + if (!CFHeaderOrErr) + return CFHeaderOrErr.takeError(); + std::vector<ChainedFixupTarget> Targets; + if (!(*CFHeaderOrErr)) + return Targets; + return Targets; +} + ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { if (!DyldInfoLoadCmd) return None; @@ -4663,6 +4845,21 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { return makeArrayRef(Ptr, DyldInfo.export_size); } +SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const { + if (!FuncStartsLoadCmd) + return {}; + + auto InfoOrErr = + getStructOrErr<MachO::linkedit_data_command>(*this, FuncStartsLoadCmd); + if (!InfoOrErr) + return {}; + + MachO::linkedit_data_command Info = InfoOrErr.get(); + SmallVector<uint64_t, 8> FunctionStarts; + this->ReadULEB128s(Info.dataoff, FunctionStarts); + return std::move(FunctionStarts); +} + ArrayRef<uint8_t> MachOObjectFile::getUuid() const { if (!UuidLoadCmd) return None; @@ -4778,3 +4975,23 @@ MachOObjectFile::mapReflectionSectionNameToEnumValue( .Default(llvm::binaryformat::Swift5ReflectionSectionKind::unknown); #undef HANDLE_SWIFT_SECTION } + +bool MachOObjectFile::isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { + switch (Arch) { + case Triple::x86: + return RelocType == MachO::GENERIC_RELOC_SECTDIFF || + RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF; + case Triple::x86_64: + return RelocType == MachO::X86_64_RELOC_SUBTRACTOR; + case Triple::arm: + case Triple::thumb: + return RelocType == MachO::ARM_RELOC_SECTDIFF || + RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF || + RelocType == MachO::ARM_RELOC_HALF || + RelocType == MachO::ARM_RELOC_HALF_SECTDIFF; + case Triple::aarch64: + return RelocType == MachO::ARM64_RELOC_SUBTRACTOR; + default: + return false; + } +} |