forked from OSchip/llvm-project
[llvm-objdump] Support dumping segment information with -chained_fixups
This commit adds the definitions for `dyld_chained_starts_in_image`, `dyld_chained_starts_in_segment`, and related enums. Dumping their contents is possible with the -chained_fixups flag of llvm-otool. The chained-fixups.yaml test was changed to cover bindings/rebases, as well as weak imports, weak symbols and flat namespace symbols. Now that we have actual fixup entries, the __DATA segment contains data that would need to be hexdumped in YAML. We also test empty pages (to look for the "DYLD_CHAINED_PTR_START_NONE" annotation), so the YAML would end up quite large. So instead, this commit includes a binary file. 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/D131961
This commit is contained in:
parent
ed342d9d29
commit
11443ef85d
|
@ -1015,6 +1015,29 @@ enum {
|
||||||
DYLD_CHAINED_SYMBOL_ZLIB = 1,
|
DYLD_CHAINED_SYMBOL_ZLIB = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Values for dyld_chained_starts_in_segment::page_start.
|
||||||
|
enum {
|
||||||
|
DYLD_CHAINED_PTR_START_NONE = 0xFFFF,
|
||||||
|
DYLD_CHAINED_PTR_START_MULTI = 0x8000,
|
||||||
|
DYLD_CHAINED_PTR_START_LAST = 0x8000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Values for dyld_chained_starts_in_segment::pointer_format.
|
||||||
|
enum {
|
||||||
|
DYLD_CHAINED_PTR_ARM64E = 1,
|
||||||
|
DYLD_CHAINED_PTR_64 = 2,
|
||||||
|
DYLD_CHAINED_PTR_32 = 3,
|
||||||
|
DYLD_CHAINED_PTR_32_CACHE = 4,
|
||||||
|
DYLD_CHAINED_PTR_32_FIRMWARE = 5,
|
||||||
|
DYLD_CHAINED_PTR_64_OFFSET = 6,
|
||||||
|
DYLD_CHAINED_PTR_ARM64E_KERNEL = 7,
|
||||||
|
DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8,
|
||||||
|
DYLD_CHAINED_PTR_ARM64E_USERLAND = 9,
|
||||||
|
DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10,
|
||||||
|
DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11,
|
||||||
|
DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12,
|
||||||
|
};
|
||||||
|
|
||||||
/// Structs for dyld chained fixups.
|
/// Structs for dyld chained fixups.
|
||||||
/// dyld_chained_fixups_header is the data pointed to by LC_DYLD_CHAINED_FIXUPS
|
/// dyld_chained_fixups_header is the data pointed to by LC_DYLD_CHAINED_FIXUPS
|
||||||
/// load command.
|
/// load command.
|
||||||
|
@ -1036,6 +1059,17 @@ struct dyld_chained_starts_in_image {
|
||||||
uint32_t seg_info_offset[1];
|
uint32_t seg_info_offset[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dyld_chained_starts_in_segment {
|
||||||
|
uint32_t size; ///< Size of this, including chain_starts entries
|
||||||
|
uint16_t page_size; ///< Page size in bytes (0x1000 or 0x4000)
|
||||||
|
uint16_t pointer_format; ///< DYLD_CHAINED_PTR*
|
||||||
|
uint64_t segment_offset; ///< VM offset from the __TEXT segment
|
||||||
|
uint32_t max_valid_pointer; ///< Values beyond this are not pointers on 32-bit
|
||||||
|
uint16_t page_count; ///< Length of the page_start array
|
||||||
|
uint16_t page_start[1]; ///< Page offset of first fixup on each page, or
|
||||||
|
///< DYLD_CHAINED_PTR_START_NONE if no fixups
|
||||||
|
};
|
||||||
|
|
||||||
// Byte order swapping functions for MachO structs
|
// Byte order swapping functions for MachO structs
|
||||||
|
|
||||||
inline void swapStruct(fat_header &mh) {
|
inline void swapStruct(fat_header &mh) {
|
||||||
|
@ -2053,6 +2087,22 @@ inline void swapStruct(dyld_chained_fixups_header &C) {
|
||||||
sys::swapByteOrder(C.symbols_format);
|
sys::swapByteOrder(C.symbols_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void swapStruct(dyld_chained_starts_in_image &C) {
|
||||||
|
sys::swapByteOrder(C.seg_count);
|
||||||
|
// getStructOrErr() cannot copy the variable-length seg_info_offset array.
|
||||||
|
// Its elements must be byte swapped manually.
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swapStruct(dyld_chained_starts_in_segment &C) {
|
||||||
|
sys::swapByteOrder(C.size);
|
||||||
|
sys::swapByteOrder(C.page_size);
|
||||||
|
sys::swapByteOrder(C.pointer_format);
|
||||||
|
sys::swapByteOrder(C.segment_offset);
|
||||||
|
sys::swapByteOrder(C.max_valid_pointer);
|
||||||
|
sys::swapByteOrder(C.page_count);
|
||||||
|
// seg_info_offset entries must be byte swapped manually.
|
||||||
|
}
|
||||||
|
|
||||||
/* code signing attributes of a process */
|
/* code signing attributes of a process */
|
||||||
|
|
||||||
enum CodeSignAttrs {
|
enum CodeSignAttrs {
|
||||||
|
|
|
@ -685,10 +685,33 @@ public:
|
||||||
ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
|
ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
|
||||||
ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
|
ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
|
||||||
ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
|
ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
|
||||||
/// If the optional is None, no header was found, but the object was well-formed.
|
/// If the optional is None, no header was found, but the object was
|
||||||
|
/// well-formed.
|
||||||
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
||||||
getChainedFixupsHeader() const;
|
getChainedFixupsHeader() const;
|
||||||
Expected<std::vector<ChainedFixupTarget>> getDyldChainedFixupTargets() const;
|
Expected<std::vector<ChainedFixupTarget>> getDyldChainedFixupTargets() const;
|
||||||
|
|
||||||
|
// Note: This is a limited, temporary API, which will be removed when Apple
|
||||||
|
// upstreams their implementation. Please do not rely on this.
|
||||||
|
Expected<Optional<MachO::linkedit_data_command>>
|
||||||
|
getChainedFixupsLoadCommand() const;
|
||||||
|
struct ChainedFixupsSegment {
|
||||||
|
ChainedFixupsSegment(uint8_t SegIdx, uint32_t Offset,
|
||||||
|
const MachO::dyld_chained_starts_in_segment &Header,
|
||||||
|
std::vector<uint16_t> &&PageStarts)
|
||||||
|
: SegIdx(SegIdx), Offset(Offset), Header(Header),
|
||||||
|
PageStarts(PageStarts){};
|
||||||
|
|
||||||
|
uint32_t SegIdx;
|
||||||
|
uint32_t Offset; // dyld_chained_starts_in_image::seg_info_offset[SegIdx]
|
||||||
|
MachO::dyld_chained_starts_in_segment Header;
|
||||||
|
std::vector<uint16_t> PageStarts; // page_start[] entries, host endianness
|
||||||
|
};
|
||||||
|
// Returns the number of sections listed in dyld_chained_starts_in_image, and
|
||||||
|
// a ChainedFixupsSegment for each segment that has fixups.
|
||||||
|
Expected<std::pair<size_t, std::vector<ChainedFixupsSegment>>>
|
||||||
|
getChainedFixupsSegments() const;
|
||||||
|
|
||||||
ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
|
ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
|
||||||
SmallVector<uint64_t> getFunctionStarts() const;
|
SmallVector<uint64_t> getFunctionStarts() const;
|
||||||
ArrayRef<uint8_t> getUuid() const;
|
ArrayRef<uint8_t> getUuid() const;
|
||||||
|
|
|
@ -4765,8 +4765,8 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
|
||||||
return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
|
return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
Expected<Optional<MachO::linkedit_data_command>>
|
||||||
MachOObjectFile::getChainedFixupsHeader() const {
|
MachOObjectFile::getChainedFixupsLoadCommand() const {
|
||||||
// Load the dyld chained fixups load command.
|
// Load the dyld chained fixups load command.
|
||||||
if (!DyldChainedFixupsLoadCmd)
|
if (!DyldChainedFixupsLoadCmd)
|
||||||
return llvm::None;
|
return llvm::None;
|
||||||
|
@ -4774,13 +4774,28 @@ MachOObjectFile::getChainedFixupsHeader() const {
|
||||||
*this, DyldChainedFixupsLoadCmd);
|
*this, DyldChainedFixupsLoadCmd);
|
||||||
if (!DyldChainedFixupsOrErr)
|
if (!DyldChainedFixupsOrErr)
|
||||||
return DyldChainedFixupsOrErr.takeError();
|
return DyldChainedFixupsOrErr.takeError();
|
||||||
MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get();
|
const MachO::linkedit_data_command &DyldChainedFixups =
|
||||||
|
*DyldChainedFixupsOrErr;
|
||||||
|
|
||||||
// If the load command is present but the data offset has been zeroed out,
|
// 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).
|
// as is the case for dylib stubs, return None (no error).
|
||||||
|
if (!DyldChainedFixups.dataoff)
|
||||||
|
return llvm::None;
|
||||||
|
return DyldChainedFixups;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expected<Optional<MachO::dyld_chained_fixups_header>>
|
||||||
|
MachOObjectFile::getChainedFixupsHeader() const {
|
||||||
|
auto CFOrErr = getChainedFixupsLoadCommand();
|
||||||
|
if (!CFOrErr)
|
||||||
|
return CFOrErr.takeError();
|
||||||
|
if (!CFOrErr->has_value())
|
||||||
|
return llvm::None;
|
||||||
|
|
||||||
|
const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
|
||||||
|
|
||||||
uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;
|
uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;
|
||||||
if (CFHeaderOffset == 0)
|
uint64_t CFSize = DyldChainedFixups.datasize;
|
||||||
return DyldChainedFixupsOrErr.takeError();
|
|
||||||
|
|
||||||
// Load the dyld chained fixups header.
|
// Load the dyld chained fixups header.
|
||||||
const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
|
const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
|
||||||
|
@ -4808,7 +4823,7 @@ MachOObjectFile::getChainedFixupsHeader() const {
|
||||||
Twine(CFHeader.starts_offset) +
|
Twine(CFHeader.starts_offset) +
|
||||||
" overlaps with chained fixups header");
|
" overlaps with chained fixups header");
|
||||||
}
|
}
|
||||||
uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize;
|
uint32_t EndOffset = CFHeaderOffset + CFSize;
|
||||||
if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) >
|
if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) >
|
||||||
EndOffset) {
|
EndOffset) {
|
||||||
return malformedError(Twine("bad chained fixups: image starts end ") +
|
return malformedError(Twine("bad chained fixups: image starts end ") +
|
||||||
|
@ -4820,6 +4835,95 @@ MachOObjectFile::getChainedFixupsHeader() const {
|
||||||
return CFHeader;
|
return CFHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expected<std::pair<size_t, std::vector<MachOObjectFile::ChainedFixupsSegment>>>
|
||||||
|
MachOObjectFile::getChainedFixupsSegments() const {
|
||||||
|
auto CFOrErr = getChainedFixupsLoadCommand();
|
||||||
|
if (!CFOrErr)
|
||||||
|
return CFOrErr.takeError();
|
||||||
|
|
||||||
|
std::vector<MachOObjectFile::ChainedFixupsSegment> Segments;
|
||||||
|
if (!CFOrErr->has_value())
|
||||||
|
return std::make_pair(0, Segments);
|
||||||
|
|
||||||
|
const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr;
|
||||||
|
|
||||||
|
auto HeaderOrErr = getChainedFixupsHeader();
|
||||||
|
if (!HeaderOrErr)
|
||||||
|
return HeaderOrErr.takeError();
|
||||||
|
if (!HeaderOrErr->has_value())
|
||||||
|
return std::make_pair(0, Segments);
|
||||||
|
const MachO::dyld_chained_fixups_header &Header = **HeaderOrErr;
|
||||||
|
|
||||||
|
const char *Contents = getPtr(*this, DyldChainedFixups.dataoff);
|
||||||
|
|
||||||
|
auto ImageStartsOrErr = getStructOrErr<MachO::dyld_chained_starts_in_image>(
|
||||||
|
*this, Contents + Header.starts_offset);
|
||||||
|
if (!ImageStartsOrErr)
|
||||||
|
return ImageStartsOrErr.takeError();
|
||||||
|
const MachO::dyld_chained_starts_in_image &ImageStarts = *ImageStartsOrErr;
|
||||||
|
|
||||||
|
const char *SegOffsPtr =
|
||||||
|
Contents + Header.starts_offset +
|
||||||
|
offsetof(MachO::dyld_chained_starts_in_image, seg_info_offset);
|
||||||
|
const char *SegOffsEnd =
|
||||||
|
SegOffsPtr + ImageStarts.seg_count * sizeof(uint32_t);
|
||||||
|
if (SegOffsEnd > Contents + DyldChainedFixups.datasize)
|
||||||
|
return malformedError(
|
||||||
|
"bad chained fixups: seg_info_offset extends past end");
|
||||||
|
|
||||||
|
const char *LastSegEnd = nullptr;
|
||||||
|
for (size_t I = 0, N = ImageStarts.seg_count; I < N; ++I) {
|
||||||
|
auto OffOrErr =
|
||||||
|
getStructOrErr<uint32_t>(*this, SegOffsPtr + I * sizeof(uint32_t));
|
||||||
|
if (!OffOrErr)
|
||||||
|
return OffOrErr.takeError();
|
||||||
|
// seg_info_offset == 0 means there is no associated starts_in_segment
|
||||||
|
// entry.
|
||||||
|
if (!*OffOrErr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto Fail = [&](Twine Message) {
|
||||||
|
return malformedError("bad chained fixups: segment info" + Twine(I) +
|
||||||
|
" at offset " + Twine(*OffOrErr) + Message);
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *SegPtr = Contents + Header.starts_offset + *OffOrErr;
|
||||||
|
if (LastSegEnd && SegPtr < LastSegEnd)
|
||||||
|
return Fail(" overlaps with previous segment info");
|
||||||
|
|
||||||
|
auto SegOrErr =
|
||||||
|
getStructOrErr<MachO::dyld_chained_starts_in_segment>(*this, SegPtr);
|
||||||
|
if (!SegOrErr)
|
||||||
|
return SegOrErr.takeError();
|
||||||
|
const MachO::dyld_chained_starts_in_segment &Seg = *SegOrErr;
|
||||||
|
|
||||||
|
LastSegEnd = SegPtr + Seg.size;
|
||||||
|
if (Seg.pointer_format < 1 || Seg.pointer_format > 12)
|
||||||
|
return Fail(" has unknown pointer format: " + Twine(Seg.pointer_format));
|
||||||
|
|
||||||
|
const char *PageStart =
|
||||||
|
SegPtr + offsetof(MachO::dyld_chained_starts_in_segment, page_start);
|
||||||
|
const char *PageEnd = PageStart + Seg.page_count * sizeof(uint16_t);
|
||||||
|
if (PageEnd > SegPtr + Seg.size)
|
||||||
|
return Fail(" : page_starts extend past seg_info size");
|
||||||
|
|
||||||
|
// FIXME: This does not account for multiple offsets on a single page
|
||||||
|
// (DYLD_CHAINED_PTR_START_MULTI; 32-bit only).
|
||||||
|
std::vector<uint16_t> PageStarts;
|
||||||
|
for (size_t PageIdx = 0; PageIdx < Seg.page_count; ++PageIdx) {
|
||||||
|
uint16_t Start;
|
||||||
|
memcpy(&Start, PageStart + PageIdx * sizeof(uint16_t), sizeof(uint16_t));
|
||||||
|
if (isLittleEndian() != sys::IsLittleEndianHost)
|
||||||
|
sys::swapByteOrder(Start);
|
||||||
|
PageStarts.push_back(Start);
|
||||||
|
}
|
||||||
|
|
||||||
|
Segments.emplace_back(I, *OffOrErr, Seg, std::move(PageStarts));
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(ImageStarts.seg_count, Segments);
|
||||||
|
}
|
||||||
|
|
||||||
Expected<std::vector<ChainedFixupTarget>>
|
Expected<std::vector<ChainedFixupTarget>>
|
||||||
MachOObjectFile::getDyldChainedFixupTargets() const {
|
MachOObjectFile::getDyldChainedFixupTargets() const {
|
||||||
auto CFHeaderOrErr = getChainedFixupsHeader();
|
auto CFHeaderOrErr = getChainedFixupsHeader();
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,86 @@
|
||||||
|
RUN: llvm-objdump -p %p/Inputs/chained-fixups.macho-x86_64 | FileCheck %s
|
||||||
|
RUN: llvm-otool -l %p/Inputs/chained-fixups.macho-x86_64 | FileCheck %s
|
||||||
|
|
||||||
|
CHECK: LC_DYLD_CHAINED_FIXUPS
|
||||||
|
CHECK: LC_DYLD_EXPORTS_TRIE
|
||||||
|
|
||||||
|
RUN: llvm-objdump --macho --chained-fixups %p/Inputs/chained-fixups.macho-x86_64 | \
|
||||||
|
RUN: FileCheck --check-prefix=DETAILS -DNAME=%p/Inputs/chained-fixups.macho-x86_64 %s
|
||||||
|
RUN: llvm-otool -chained_fixups %p/Inputs/chained-fixups.macho-x86_64 | \
|
||||||
|
RUN: FileCheck --check-prefix=DETAILS -DNAME=%p/Inputs/chained-fixups.macho-x86_64 %s
|
||||||
|
|
||||||
|
DETAILS: [[NAME]]:
|
||||||
|
DETAILS-NEXT: chained fixups header (LC_DYLD_CHAINED_FIXUPS)
|
||||||
|
DETAILS-NEXT: fixups_version = 0
|
||||||
|
DETAILS-NEXT: starts_offset = 32
|
||||||
|
DETAILS-NEXT: imports_offset = 112
|
||||||
|
DETAILS-NEXT: symbols_offset = 132
|
||||||
|
DETAILS-NEXT: imports_count = 5
|
||||||
|
DETAILS-NEXT: imports_format = 1 (DYLD_CHAINED_IMPORT)
|
||||||
|
DETAILS-NEXT: symbols_format = 0
|
||||||
|
DETAILS-NEXT: chained starts in image
|
||||||
|
DETAILS-NEXT: seg_count = 4
|
||||||
|
DETAILS-NEXT: seg_offset[0] = 0 (__TEXT)
|
||||||
|
DETAILS-NEXT: seg_offset[1] = 24 (__DATA_CONST)
|
||||||
|
DETAILS-NEXT: seg_offset[2] = 48 (__DATA)
|
||||||
|
DETAILS-NEXT: seg_offset[3] = 0 (__LINKEDIT)
|
||||||
|
DETAILS-NEXT: chained starts in segment 1 (__DATA_CONST)
|
||||||
|
DETAILS-NEXT: size = 24
|
||||||
|
DETAILS-NEXT: page_size = 0x1000
|
||||||
|
DETAILS-NEXT: pointer_format = 6 (DYLD_CHAINED_PTR_64_OFFSET)
|
||||||
|
DETAILS-NEXT: segment_offset = 0x3e0
|
||||||
|
DETAILS-NEXT: max_valid_pointer = 0
|
||||||
|
DETAILS-NEXT: page_count = 1
|
||||||
|
DETAILS-NEXT: page_start[0] = 0
|
||||||
|
DETAILS-NEXT: chained starts in segment 2 (__DATA)
|
||||||
|
DETAILS-NEXT: size = 30
|
||||||
|
DETAILS-NEXT: page_size = 0x1000
|
||||||
|
DETAILS-NEXT: pointer_format = 6 (DYLD_CHAINED_PTR_64_OFFSET)
|
||||||
|
DETAILS-NEXT: segment_offset = 0x3f0
|
||||||
|
DETAILS-NEXT: max_valid_pointer = 0
|
||||||
|
DETAILS-NEXT: page_count = 4
|
||||||
|
DETAILS-NEXT: page_start[0] = 0
|
||||||
|
DETAILS-NEXT: page_start[1] = 32
|
||||||
|
DETAILS-NEXT: page_start[2] = 65535 (DYLD_CHAINED_PTR_START_NONE)
|
||||||
|
DETAILS-NEXT: page_start[3] = 32
|
||||||
|
|
||||||
|
## This test checks that the output is identical to that of cctools-1001.2 (XCode 14)
|
||||||
|
## The input was generated from the following files:
|
||||||
|
##
|
||||||
|
## --- dylib.s:
|
||||||
|
## .data
|
||||||
|
## .globl _weak, _dylib, _weakImport
|
||||||
|
## .weak_definition _weak
|
||||||
|
## _weak:
|
||||||
|
## _dylib:
|
||||||
|
## _weakImport:
|
||||||
|
##
|
||||||
|
## $ clang --target=x86_64-apple-macos12 -dynamiclib dylib.s -o libdylib.dylib
|
||||||
|
##
|
||||||
|
## --- chained-fixups.s:
|
||||||
|
## .global _local, _weak, _weakLocal, _dylib, _weakImport, _dynamicLookup
|
||||||
|
## .weak_definition _weakLocal
|
||||||
|
## .weak_reference _weakImport
|
||||||
|
##
|
||||||
|
## .data
|
||||||
|
## .p2align 4
|
||||||
|
## _local:
|
||||||
|
## _weakLocal:
|
||||||
|
## .quad _local
|
||||||
|
## .space 8
|
||||||
|
## .quad _weak
|
||||||
|
## .space 4096
|
||||||
|
## .p2align 4
|
||||||
|
## .quad _weakLocal
|
||||||
|
## .space 8172
|
||||||
|
## .p2align 4
|
||||||
|
## .quad _dylib
|
||||||
|
## .quad _dylib + 42
|
||||||
|
##
|
||||||
|
## .section __DATA_CONST,__const
|
||||||
|
## .p2align 4
|
||||||
|
## .quad _weakImport
|
||||||
|
## .quad _dynamicLookup
|
||||||
|
##
|
||||||
|
## $ clang --target=x86_64-apple-macos12 -dynamiclib -L. -ldylib chained-fixups.s \
|
||||||
|
## -o chained-fixups.macho-x86_64 -Wl,-segalign,0x10 -Wl,-U,_dynamicLookup
|
|
@ -1,151 +0,0 @@
|
||||||
# RUN: yaml2obj %s -o %t
|
|
||||||
# RUN: llvm-objdump -p %t | FileCheck %s
|
|
||||||
# RUN: llvm-otool -l %t | FileCheck %s
|
|
||||||
|
|
||||||
# CHECK: LC_DYLD_CHAINED_FIXUPS
|
|
||||||
# CHECK: LC_DYLD_EXPORTS_TRIE
|
|
||||||
|
|
||||||
# RUN: llvm-objdump --macho --chained-fixups %t | \
|
|
||||||
# RUN: FileCheck --check-prefix=DETAILS -DNAME=%t %s
|
|
||||||
# RUN: llvm-otool -chained_fixups %t | \
|
|
||||||
# RUN: FileCheck --check-prefix=DETAILS -DNAME=%t %s
|
|
||||||
|
|
||||||
# DETAILS: [[NAME]]:
|
|
||||||
# DETAILS-NEXT: chained fixups header (LC_DYLD_CHAINED_FIXUPS)
|
|
||||||
# DETAILS-NEXT: fixups_version = 0
|
|
||||||
# DETAILS-NEXT: starts_offset = 32
|
|
||||||
# DETAILS-NEXT: imports_offset = 44
|
|
||||||
# DETAILS-NEXT: symbols_offset = 44
|
|
||||||
# DETAILS-NEXT: imports_count = 0
|
|
||||||
# DETAILS-NEXT: imports_format = 1 (DYLD_CHAINED_IMPORT)
|
|
||||||
# DETAILS-NEXT: symbols_format = 0
|
|
||||||
|
|
||||||
## This yaml is from a dylib produced by ld64
|
|
||||||
## echo ".global _foo\n_foo" > dylib.s
|
|
||||||
## clang -target=x86_64-apple-macos12 -dynamiclib -isysroot Inputs/MacOSX.sdk dylib.s -o libdylib.dylib
|
|
||||||
## obj2yaml --raw-segment=data libdylib.dylib
|
|
||||||
--- !mach-o
|
|
||||||
IsLittleEndian: true
|
|
||||||
FileHeader:
|
|
||||||
magic: 0xFEEDFACF
|
|
||||||
cputype: 0x1000007
|
|
||||||
cpusubtype: 0x3
|
|
||||||
filetype: 0x6
|
|
||||||
ncmds: 13
|
|
||||||
sizeofcmds: 568
|
|
||||||
flags: 0x100085
|
|
||||||
reserved: 0x0
|
|
||||||
LoadCommands:
|
|
||||||
- cmd: LC_SEGMENT_64
|
|
||||||
cmdsize: 152
|
|
||||||
segname: __TEXT
|
|
||||||
vmaddr: 0
|
|
||||||
vmsize: 16384
|
|
||||||
fileoff: 0
|
|
||||||
filesize: 16384
|
|
||||||
maxprot: 5
|
|
||||||
initprot: 5
|
|
||||||
nsects: 1
|
|
||||||
flags: 0
|
|
||||||
Sections:
|
|
||||||
- sectname: __text
|
|
||||||
segname: __TEXT
|
|
||||||
addr: 0x4000
|
|
||||||
size: 0
|
|
||||||
offset: 0x4000
|
|
||||||
align: 0
|
|
||||||
reloff: 0x0
|
|
||||||
nreloc: 0
|
|
||||||
flags: 0x80000400
|
|
||||||
reserved1: 0x0
|
|
||||||
reserved2: 0x0
|
|
||||||
reserved3: 0x0
|
|
||||||
content: ''
|
|
||||||
- cmd: LC_SEGMENT_64
|
|
||||||
cmdsize: 72
|
|
||||||
segname: __LINKEDIT
|
|
||||||
vmaddr: 16384
|
|
||||||
vmsize: 16384
|
|
||||||
fileoff: 16384
|
|
||||||
filesize: 96
|
|
||||||
maxprot: 1
|
|
||||||
initprot: 1
|
|
||||||
nsects: 0
|
|
||||||
flags: 0
|
|
||||||
- cmd: LC_ID_DYLIB
|
|
||||||
cmdsize: 48
|
|
||||||
dylib:
|
|
||||||
name: 24
|
|
||||||
timestamp: 1
|
|
||||||
current_version: 0
|
|
||||||
compatibility_version: 0
|
|
||||||
Content: libdylib.dylib
|
|
||||||
ZeroPadBytes: 3
|
|
||||||
- cmd: LC_DYLD_CHAINED_FIXUPS
|
|
||||||
cmdsize: 16
|
|
||||||
dataoff: 16384
|
|
||||||
datasize: 48
|
|
||||||
- cmd: LC_DYLD_EXPORTS_TRIE
|
|
||||||
cmdsize: 16
|
|
||||||
dataoff: 16432
|
|
||||||
datasize: 16
|
|
||||||
- cmd: LC_SYMTAB
|
|
||||||
cmdsize: 24
|
|
||||||
symoff: 16456
|
|
||||||
nsyms: 1
|
|
||||||
stroff: 16472
|
|
||||||
strsize: 8
|
|
||||||
- cmd: LC_DYSYMTAB
|
|
||||||
cmdsize: 80
|
|
||||||
ilocalsym: 0
|
|
||||||
nlocalsym: 0
|
|
||||||
iextdefsym: 0
|
|
||||||
nextdefsym: 1
|
|
||||||
iundefsym: 1
|
|
||||||
nundefsym: 0
|
|
||||||
tocoff: 0
|
|
||||||
ntoc: 0
|
|
||||||
modtaboff: 0
|
|
||||||
nmodtab: 0
|
|
||||||
extrefsymoff: 0
|
|
||||||
nextrefsyms: 0
|
|
||||||
indirectsymoff: 0
|
|
||||||
nindirectsyms: 0
|
|
||||||
extreloff: 0
|
|
||||||
nextrel: 0
|
|
||||||
locreloff: 0
|
|
||||||
nlocrel: 0
|
|
||||||
- cmd: LC_UUID
|
|
||||||
cmdsize: 24
|
|
||||||
uuid: 52409B91-DF59-346A-A63F-D4E6FFDC3E04
|
|
||||||
- cmd: LC_BUILD_VERSION
|
|
||||||
cmdsize: 32
|
|
||||||
platform: 1
|
|
||||||
minos: 786432
|
|
||||||
sdk: 851968
|
|
||||||
ntools: 1
|
|
||||||
Tools:
|
|
||||||
- tool: 3
|
|
||||||
version: 53674242
|
|
||||||
- cmd: LC_SOURCE_VERSION
|
|
||||||
cmdsize: 16
|
|
||||||
version: 0
|
|
||||||
- cmd: LC_LOAD_DYLIB
|
|
||||||
cmdsize: 56
|
|
||||||
dylib:
|
|
||||||
name: 24
|
|
||||||
timestamp: 2
|
|
||||||
current_version: 65793
|
|
||||||
compatibility_version: 65536
|
|
||||||
Content: '/usr/lib/libSystem.dylib'
|
|
||||||
ZeroPadBytes: 8
|
|
||||||
- cmd: LC_FUNCTION_STARTS
|
|
||||||
cmdsize: 16
|
|
||||||
dataoff: 16448
|
|
||||||
datasize: 8
|
|
||||||
- cmd: LC_DATA_IN_CODE
|
|
||||||
cmdsize: 16
|
|
||||||
dataoff: 16456
|
|
||||||
datasize: 0
|
|
||||||
__LINKEDIT: 00000000200000002C0000002C000000000000000100000000000000000000000200000000000000000000000000000000015F666F6F000804008080010000000000000000000000020000000F010000004000000000000020005F666F6F0000
|
|
||||||
...
|
|
|
@ -1195,6 +1195,20 @@ static void printMachOChainedFixups(object::MachOObjectFile *Obj) {
|
||||||
reportError(std::move(Err), Obj->getFileName());
|
reportError(std::move(Err), Obj->getFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SmallVector<std::string> GetSegmentNames(object::MachOObjectFile *O) {
|
||||||
|
SmallVector<std::string> Ret;
|
||||||
|
for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) {
|
||||||
|
if (Command.C.cmd == MachO::LC_SEGMENT) {
|
||||||
|
MachO::segment_command SLC = O->getSegmentLoadCommand(Command);
|
||||||
|
Ret.push_back(SLC.segname);
|
||||||
|
} else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
|
||||||
|
MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command);
|
||||||
|
Ret.push_back(SLC.segname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
|
PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
|
||||||
outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
|
outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
|
||||||
|
@ -1224,6 +1238,50 @@ PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
|
||||||
outs() << '\n';
|
outs() << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr std::array<StringRef, 13> PointerFormats{
|
||||||
|
"DYLD_CHAINED_PTR_ARM64E",
|
||||||
|
"DYLD_CHAINED_PTR_64",
|
||||||
|
"DYLD_CHAINED_PTR_32",
|
||||||
|
"DYLD_CHAINED_PTR_32_CACHE",
|
||||||
|
"DYLD_CHAINED_PTR_32_FIRMWARE",
|
||||||
|
"DYLD_CHAINED_PTR_64_OFFSET",
|
||||||
|
"DYLD_CHAINED_PTR_ARM64E_KERNEL",
|
||||||
|
"DYLD_CHAINED_PTR_64_KERNEL_CACHE",
|
||||||
|
"DYLD_CHAINED_PTR_ARM64E_USERLAND",
|
||||||
|
"DYLD_CHAINED_PTR_ARM64E_FIRMWARE",
|
||||||
|
"DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE",
|
||||||
|
"DYLD_CHAINED_PTR_ARM64E_USERLAND24",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
PrintChainedFixupsSegment(const MachOObjectFile::ChainedFixupsSegment &Segment,
|
||||||
|
StringRef SegName) {
|
||||||
|
outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName
|
||||||
|
<< ")\n";
|
||||||
|
outs() << " size = " << Segment.Header.size << '\n';
|
||||||
|
outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size)
|
||||||
|
<< '\n';
|
||||||
|
|
||||||
|
outs() << " pointer_format = " << Segment.Header.pointer_format;
|
||||||
|
if ((Segment.Header.pointer_format - 1) <
|
||||||
|
MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24)
|
||||||
|
outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")";
|
||||||
|
outs() << '\n';
|
||||||
|
|
||||||
|
outs() << " segment_offset = "
|
||||||
|
<< format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n';
|
||||||
|
outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer
|
||||||
|
<< '\n';
|
||||||
|
outs() << " page_count = " << Segment.Header.page_count << '\n';
|
||||||
|
for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) {
|
||||||
|
outs() << " page_start[" << Index << "] = " << PageStart;
|
||||||
|
// FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only)
|
||||||
|
if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE)
|
||||||
|
outs() << " (DYLD_CHAINED_PTR_START_NONE)";
|
||||||
|
outs() << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void PrintChainedFixups(MachOObjectFile *O) {
|
static void PrintChainedFixups(MachOObjectFile *O) {
|
||||||
// MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
|
// MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
|
||||||
// FIXME: Support chained fixups in __TEXT,__chain_starts section too.
|
// FIXME: Support chained fixups in __TEXT,__chain_starts section too.
|
||||||
|
@ -1234,6 +1292,28 @@ static void PrintChainedFixups(MachOObjectFile *O) {
|
||||||
|
|
||||||
PrintChainedFixupsHeader(*ChainedFixupHeader);
|
PrintChainedFixupsHeader(*ChainedFixupHeader);
|
||||||
|
|
||||||
|
auto [SegCount, Segments] =
|
||||||
|
unwrapOrError(O->getChainedFixupsSegments(), O->getFileName());
|
||||||
|
|
||||||
|
auto SegNames = GetSegmentNames(O);
|
||||||
|
|
||||||
|
size_t StartsIdx = 0;
|
||||||
|
outs() << "chained starts in image\n";
|
||||||
|
outs() << " seg_count = " << SegCount << '\n';
|
||||||
|
for (size_t I = 0; I < SegCount; ++I) {
|
||||||
|
uint64_t SegOffset = 0;
|
||||||
|
if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) {
|
||||||
|
SegOffset = Segments[StartsIdx].Offset;
|
||||||
|
++StartsIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
outs() << " seg_offset[" << I << "] = " << SegOffset << " ("
|
||||||
|
<< SegNames[I] << ")\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const MachOObjectFile::ChainedFixupsSegment &S : Segments)
|
||||||
|
PrintChainedFixupsSegment(S, SegNames[S.SegIdx]);
|
||||||
|
|
||||||
// FIXME: Print more things.
|
// FIXME: Print more things.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue