|
19 | 19 | #include "llvm/ADT/StringSwitch.h"
|
20 | 20 | #include "llvm/ADT/Triple.h"
|
21 | 21 | #include "llvm/ADT/Twine.h"
|
| 22 | +#include "llvm/ADT/bit.h" |
22 | 23 | #include "llvm/BinaryFormat/MachO.h"
|
23 | 24 | #include "llvm/BinaryFormat/Swift.h"
|
24 | 25 | #include "llvm/Object/Error.h"
|
@@ -4924,15 +4925,122 @@ MachOObjectFile::getChainedFixupsSegments() const {
|
4924 | 4925 | return std::make_pair(ImageStarts.seg_count, Segments);
|
4925 | 4926 | }
|
4926 | 4927 |
|
| 4928 | +// The special library ordinals have a negative value, but they are encoded in |
| 4929 | +// an unsigned bitfield, so we need to sign extend the value. |
| 4930 | +template <typename T> static int getEncodedOrdinal(T Value) { |
| 4931 | + if (Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE) || |
| 4932 | + Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) || |
| 4933 | + Value == static_cast<T>(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP)) |
| 4934 | + return SignExtend32<sizeof(T) * CHAR_BIT>(Value); |
| 4935 | + return Value; |
| 4936 | +} |
| 4937 | + |
| 4938 | +template <typename T, unsigned N> |
| 4939 | +static std::array<T, N> getArray(const MachOObjectFile &O, const void *Ptr) { |
| 4940 | + std::array<T, N> RawValue; |
| 4941 | + memcpy(RawValue.data(), Ptr, N * sizeof(T)); |
| 4942 | + if (O.isLittleEndian() != sys::IsLittleEndianHost) |
| 4943 | + for (auto &Element : RawValue) |
| 4944 | + sys::swapByteOrder(Element); |
| 4945 | + return RawValue; |
| 4946 | +} |
| 4947 | + |
4927 | 4948 | Expected<std::vector<ChainedFixupTarget>>
|
4928 | 4949 | MachOObjectFile::getDyldChainedFixupTargets() const {
|
| 4950 | + auto CFOrErr = getChainedFixupsLoadCommand(); |
| 4951 | + if (!CFOrErr) |
| 4952 | + return CFOrErr.takeError(); |
| 4953 | + |
| 4954 | + std::vector<ChainedFixupTarget> Targets; |
| 4955 | + if (!CFOrErr->has_value()) |
| 4956 | + return Targets; |
| 4957 | + |
| 4958 | + const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; |
| 4959 | + |
4929 | 4960 | auto CFHeaderOrErr = getChainedFixupsHeader();
|
4930 | 4961 | if (!CFHeaderOrErr)
|
4931 | 4962 | return CFHeaderOrErr.takeError();
|
4932 |
| - std::vector<ChainedFixupTarget> Targets; |
4933 | 4963 | if (!(*CFHeaderOrErr))
|
4934 | 4964 | return Targets;
|
4935 |
| - return Targets; |
| 4965 | + const MachO::dyld_chained_fixups_header &Header = **CFHeaderOrErr; |
| 4966 | + |
| 4967 | + size_t ImportSize = 0; |
| 4968 | + if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) |
| 4969 | + ImportSize = sizeof(MachO::dyld_chained_import); |
| 4970 | + else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) |
| 4971 | + ImportSize = sizeof(MachO::dyld_chained_import_addend); |
| 4972 | + else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) |
| 4973 | + ImportSize = sizeof(MachO::dyld_chained_import_addend64); |
| 4974 | + else |
| 4975 | + return malformedError("bad chained fixups: unknown imports format: " + |
| 4976 | + Twine(Header.imports_format)); |
| 4977 | + |
| 4978 | + const char *Contents = getPtr(*this, DyldChainedFixups.dataoff); |
| 4979 | + const char *Imports = Contents + Header.imports_offset; |
| 4980 | + size_t ImportsEndOffset = |
| 4981 | + Header.imports_offset + ImportSize * Header.imports_count; |
| 4982 | + const char *ImportsEnd = Contents + ImportsEndOffset; |
| 4983 | + const char *Symbols = Contents + Header.symbols_offset; |
| 4984 | + const char *SymbolsEnd = Contents + DyldChainedFixups.datasize; |
| 4985 | + |
| 4986 | + if (ImportsEnd > Symbols) |
| 4987 | + return malformedError("bad chained fixups: imports end " + |
| 4988 | + Twine(ImportsEndOffset) + " extends past end " + |
| 4989 | + Twine(DyldChainedFixups.datasize)); |
| 4990 | + |
| 4991 | + if (ImportsEnd > Symbols) |
| 4992 | + return malformedError("bad chained fixups: imports end " + |
| 4993 | + Twine(ImportsEndOffset) + " overlaps with symbols"); |
| 4994 | + |
| 4995 | + // We use bit manipulation to extract data from the bitfields. This is correct |
| 4996 | + // for both LE and BE hosts, but we assume that the object is little-endian. |
| 4997 | + if (!isLittleEndian()) |
| 4998 | + return createError("parsing big-endian chained fixups is not implemented"); |
| 4999 | + for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd; |
| 5000 | + ImportPtr += ImportSize) { |
| 5001 | + int LibOrdinal; |
| 5002 | + bool WeakImport; |
| 5003 | + uint32_t NameOffset; |
| 5004 | + uint64_t Addend; |
| 5005 | + if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) { |
| 5006 | + static_assert(sizeof(uint32_t) == sizeof(MachO::dyld_chained_import)); |
| 5007 | + auto RawValue = getArray<uint32_t, 1>(*this, ImportPtr); |
| 5008 | + |
| 5009 | + LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF); |
| 5010 | + WeakImport = (RawValue[0] >> 8) & 1; |
| 5011 | + NameOffset = RawValue[0] >> 9; |
| 5012 | + Addend = 0; |
| 5013 | + } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) { |
| 5014 | + static_assert(sizeof(uint64_t) == |
| 5015 | + sizeof(MachO::dyld_chained_import_addend)); |
| 5016 | + auto RawValue = getArray<uint32_t, 2>(*this, ImportPtr); |
| 5017 | + |
| 5018 | + LibOrdinal = getEncodedOrdinal<uint8_t>(RawValue[0] & 0xFF); |
| 5019 | + WeakImport = (RawValue[0] >> 8) & 1; |
| 5020 | + NameOffset = RawValue[0] >> 9; |
| 5021 | + Addend = bit_cast<int32_t>(RawValue[1]); |
| 5022 | + } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) { |
| 5023 | + static_assert(2 * sizeof(uint64_t) == |
| 5024 | + sizeof(MachO::dyld_chained_import_addend64)); |
| 5025 | + auto RawValue = getArray<uint64_t, 2>(*this, ImportPtr); |
| 5026 | + |
| 5027 | + LibOrdinal = getEncodedOrdinal<uint16_t>(RawValue[0] & 0xFFFF); |
| 5028 | + NameOffset = (RawValue[0] >> 16) & 1; |
| 5029 | + WeakImport = RawValue[0] >> 17; |
| 5030 | + Addend = RawValue[1]; |
| 5031 | + } else { |
| 5032 | + llvm_unreachable("Import format should have been checked"); |
| 5033 | + } |
| 5034 | + |
| 5035 | + const char *Str = Symbols + NameOffset; |
| 5036 | + if (Str >= SymbolsEnd) |
| 5037 | + return malformedError("bad chained fixups: symbol offset " + |
| 5038 | + Twine(NameOffset) + " extends past end " + |
| 5039 | + Twine(DyldChainedFixups.datasize)); |
| 5040 | + Targets.emplace_back(LibOrdinal, NameOffset, Str, Addend, WeakImport); |
| 5041 | + } |
| 5042 | + |
| 5043 | + return std::move(Targets); |
4936 | 5044 | }
|
4937 | 5045 |
|
4938 | 5046 | ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
|
|
0 commit comments