Index: llvm/include/llvm/BinaryFormat/MachO.h =================================================================== --- llvm/include/llvm/BinaryFormat/MachO.h +++ llvm/include/llvm/BinaryFormat/MachO.h @@ -1070,6 +1070,30 @@ ///< DYLD_CHAINED_PTR_START_NONE if no fixups }; +// DYLD_CHAINED_IMPORT +struct dyld_chained_import { + uint32_t lib_ordinal : 8; + uint32_t weak_import : 1; + uint32_t name_offset : 23; +}; + +// DYLD_CHAINED_IMPORT_ADDEND +struct dyld_chained_import_addend { + uint32_t lib_ordinal : 8; + uint32_t weak_import : 1; + uint32_t name_offset : 23; + int32_t addend; +}; + +// DYLD_CHAINED_IMPORT_ADDEND64 +struct dyld_chained_import_addend64 { + uint64_t lib_ordinal : 16; + uint64_t weak_import : 1; + uint64_t reserved : 15; + uint64_t name_offset : 32; + uint64_t addend; +}; + // Byte order swapping functions for MachO structs inline void swapStruct(fat_header &mh) { @@ -2103,6 +2127,29 @@ // seg_info_offset entries must be byte swapped manually. } +inline void swapStruct(dyld_chained_import &C) { + uint32_t Raw[1]; + memcpy(Raw, &C, sizeof(C)); + sys::swapByteOrder(Raw[0]); + memcpy(&C, Raw, sizeof(C)); +} + +inline void swapStruct(dyld_chained_import_addend &C) { + uint32_t Raw[2]; + memcpy(Raw, &C, sizeof(C)); + sys::swapByteOrder(Raw[0]); + sys::swapByteOrder(Raw[1]); + memcpy(&C, Raw, sizeof(C)); +} + +inline void swapStruct(dyld_chained_import_addend64 &C) { + uint64_t Raw[2]; + memcpy(Raw, &C, sizeof(C)); + sys::swapByteOrder(Raw[0]); + sys::swapByteOrder(Raw[1]); + memcpy(&C, Raw, sizeof(C)); +} + /* code signing attributes of a process */ enum CodeSignAttrs { Index: llvm/include/llvm/Object/MachO.h =================================================================== --- llvm/include/llvm/Object/MachO.h +++ llvm/include/llvm/Object/MachO.h @@ -274,12 +274,13 @@ /// symbol. E.g., C++'s "operator new". This is called a "weak bind." struct ChainedFixupTarget { public: - ChainedFixupTarget(int LibOrdinal, StringRef Symbol, uint64_t Addend, - bool WeakImport) - : LibOrdinal(LibOrdinal), SymbolName(Symbol), Addend(Addend), - WeakImport(WeakImport) {} + ChainedFixupTarget(int LibOrdinal, uint32_t NameOffset, StringRef Symbol, + uint64_t Addend, bool WeakImport) + : LibOrdinal(LibOrdinal), NameOffset(NameOffset), SymbolName(Symbol), + Addend(Addend), WeakImport(WeakImport) {} int libOrdinal() { return LibOrdinal; } + uint32_t nameOffset() { return NameOffset; } StringRef symbolName() { return SymbolName; } uint64_t addend() { return Addend; } bool weakImport() { return WeakImport; } @@ -289,6 +290,7 @@ private: int LibOrdinal; + uint32_t NameOffset; StringRef SymbolName; uint64_t Addend; bool WeakImport; Index: llvm/lib/Object/MachOObjectFile.cpp =================================================================== --- llvm/lib/Object/MachOObjectFile.cpp +++ llvm/lib/Object/MachOObjectFile.cpp @@ -4924,14 +4924,111 @@ return std::make_pair(ImageStarts.seg_count, Segments); } +// Get a signed library ordinal from the encoded 8/16 bit unsigned ordinal in +// the import data. +template static int getEncodedOrdinal(T Value) { + // These special ordinals have a negative value; everything else is positive, + // thus can remain unchanged. + if (Value == static_cast(MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE)) + return MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE; + else if (Value == static_cast(MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP)) + return MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP; + else if (Value == static_cast(MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP)) + return MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP; + return Value; +} + Expected> MachOObjectFile::getDyldChainedFixupTargets() const { + auto CFOrErr = getChainedFixupsLoadCommand(); + if (!CFOrErr) + return CFOrErr.takeError(); + + std::vector Targets; + if (!CFOrErr->has_value()) + return Targets; + + const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; + auto CFHeaderOrErr = getChainedFixupsHeader(); if (!CFHeaderOrErr) return CFHeaderOrErr.takeError(); - std::vector Targets; if (!(*CFHeaderOrErr)) return Targets; + const MachO::dyld_chained_fixups_header &Header = **CFHeaderOrErr; + + size_t ImportSize = 0; + if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) + ImportSize = sizeof(uint32_t); + else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) + ImportSize = sizeof(uint64_t); + else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) + ImportSize = 2 * sizeof(uint64_t); + else + llvm_unreachable("Unknown 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"); + + for (const char *ImportPtr = Imports; ImportPtr < ImportsEnd; + ImportPtr += ImportSize) { + int LibOrdinal; + uint32_t NameOffset; + uint64_t Addend; + bool WeakImport; + if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT) { + auto ImportOrErr = + getStructOrErr(*this, ImportPtr); + if (!ImportOrErr) + return ImportOrErr.takeError(); + LibOrdinal = GetEncodedOrdinal(ImportOrErr->lib_ordinal); + NameOffset = ImportOrErr->name_offset; + WeakImport = ImportOrErr->weak_import; + Addend = 0; + } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND) { + auto ImportOrErr = + getStructOrErr(*this, ImportPtr); + if (!ImportOrErr) + return ImportOrErr.takeError(); + LibOrdinal = GetEncodedOrdinal(ImportOrErr->lib_ordinal); + NameOffset = ImportOrErr->name_offset; + Addend = ImportOrErr->addend; + WeakImport = ImportOrErr->weak_import; + } else if (Header.imports_format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) { + auto ImportOrErr = + getStructOrErr(*this, ImportPtr); + if (!ImportOrErr) + return ImportOrErr.takeError(); + LibOrdinal = GetEncodedOrdinal(ImportOrErr->lib_ordinal); + NameOffset = ImportOrErr->name_offset; + Addend = ImportOrErr->addend; + WeakImport = ImportOrErr->weak_import; + } else { + llvm_unreachable("Unknown imports format"); + } + + 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 Targets; } Index: llvm/test/tools/llvm-objdump/MachO/chained-fixups.test =================================================================== --- llvm/test/tools/llvm-objdump/MachO/chained-fixups.test +++ llvm/test/tools/llvm-objdump/MachO/chained-fixups.test @@ -43,8 +43,30 @@ DETAILS-NEXT: page_start[1] = 32 DETAILS-NEXT: page_start[2] = 65535 (DYLD_CHAINED_PTR_START_NONE) DETAILS-NEXT: page_start[3] = 32 +DETAILS-NEXT: dyld chained import[0] +DETAILS-NEXT: lib_ordinal = -2 (flat-namespace) +DETAILS-NEXT: weak_import = 0 +DETAILS-NEXT: name_offset = 1 (_dynamicLookup) +DETAILS-NEXT: dyld chained import[1] +DETAILS-NEXT: lib_ordinal = 1 (libdylib) +DETAILS-NEXT: weak_import = 1 +DETAILS-NEXT: name_offset = 16 (_weakImport) +DETAILS-NEXT: dyld chained import[2] +DETAILS-NEXT: lib_ordinal = 1 (libdylib) +DETAILS-NEXT: weak_import = 0 +DETAILS-NEXT: name_offset = 28 (_dylib) +DETAILS-NEXT: dyld chained import[3] +DETAILS-NEXT: lib_ordinal = -3 (weak) +DETAILS-NEXT: weak_import = 0 +DETAILS-NEXT: name_offset = 35 (_weakLocal) +DETAILS-NEXT: dyld chained import[4] +DETAILS-NEXT: lib_ordinal = -3 (weak) +DETAILS-NEXT: weak_import = 0 +DETAILS-NEXT: name_offset = 46 (_weak) ## This test checks that the output is identical to that of cctools-1001.2 (XCode 14) +## FIXME: Print encoded values of the dyld_chained_import* entries +## ## The input was generated from the following files: ## ## --- dylib.s: Index: llvm/tools/llvm-objdump/MachODump.cpp =================================================================== --- llvm/tools/llvm-objdump/MachODump.cpp +++ llvm/tools/llvm-objdump/MachODump.cpp @@ -94,6 +94,8 @@ static bool ArchAll = false; static std::string ThumbTripleName; +static StringRef ordinalName(const object::MachOObjectFile *, int); + void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) { FirstPrivateHeader = InputArgs.hasArg(OBJDUMP_private_header); ExportsTrie = InputArgs.hasArg(OBJDUMP_exports_trie); @@ -1282,6 +1284,26 @@ } } +static void PrintChainedFixupTarget(ChainedFixupTarget &Target, size_t Idx, + int Format, MachOObjectFile *O) { + if (Format == MachO::DYLD_CHAINED_IMPORT) + outs() << "dyld chained import"; + else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND) + outs() << "dyld chained import addend"; + else if (Format == MachO::DYLD_CHAINED_IMPORT_ADDEND64) + outs() << "dyld chained import addend64"; + // FIXME: otool prints the encoded value as well. + outs() << '[' << Idx << "]\n"; + + outs() << " lib_ordinal = " << Target.libOrdinal() << " (" + << ordinalName(O, Target.libOrdinal()) << ")\n"; + outs() << " weak_import = " << Target.weakImport() << '\n'; + outs() << " name_offset = " << Target.nameOffset() << " (" + << Target.symbolName() << ")\n"; + if (Format != MachO::DYLD_CHAINED_IMPORT) + outs() << " addend = " << Target.addend() << '\n'; +} + static void PrintChainedFixups(MachOObjectFile *O) { // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS. // FIXME: Support chained fixups in __TEXT,__chain_starts section too. @@ -1314,7 +1336,12 @@ for (const MachOObjectFile::ChainedFixupsSegment &S : Segments) PrintChainedFixupsSegment(S, SegNames[S.SegIdx]); - // FIXME: Print more things. + auto FixupTargets = + unwrapOrError(O->getDyldChainedFixupTargets(), O->getFileName()); + + uint32_t ImportsFormat = ChainedFixupHeader->imports_format; + for (auto [Idx, Target] : enumerate(FixupTargets)) + PrintChainedFixupTarget(Target, Idx, ImportsFormat, O); } static void PrintDyldInfo(MachOObjectFile *O) { @@ -10508,6 +10535,8 @@ return "main-executable"; case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP: return "flat-namespace"; + case MachO::BIND_SPECIAL_DYLIB_WEAK_LOOKUP: + return "weak"; default: if (Ordinal > 0) { std::error_code EC =