[llvm-objdump] Start on -chained_fixups for llvm-otool

And --chained-fixups for llvm-objdump.

For now, this only prints the dyld_chained_fixups_header and adds
plumbing for the flag. This will be expanded in future commits.

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.

Update chained-fixups.yaml with a file that actually contains
the chained fixup data (`LinkEditData` doesn't encode it yet,
so use `__LINKEDIT` via `--raw-segment=data`).

Differential Revision: https://reviews.llvm.org/D131890
This commit is contained in:
Nico Weber 2022-08-15 09:06:57 -04:00
parent e114ecc5fe
commit 940e178c00
9 changed files with 155 additions and 172 deletions

View File

@ -312,6 +312,10 @@ MACH-O ONLY OPTIONS AND COMMANDS
Disassemble just the specified symbol's instructions.
.. option:: --chained-fixups
Print chained fixup information.
.. option:: --dyld_info
Print bind and rebase information used by dyld to resolve external

View File

@ -23,6 +23,10 @@ OPTIONS
Select slice of universal Mach-O file.
.. option:: -chained_fixups
Print chained fixup information.
.. option:: -C
Print linker optimization hints.

View File

@ -1002,6 +1002,19 @@ struct nlist_64 {
uint64_t n_value;
};
// Values for dyld_chained_fixups_header::imports_format.
enum {
DYLD_CHAINED_IMPORT = 1,
DYLD_CHAINED_IMPORT_ADDEND = 2,
DYLD_CHAINED_IMPORT_ADDEND64 = 3,
};
// Values for dyld_chained_fixups_header::symbols_format.
enum {
DYLD_CHAINED_SYMBOL_UNCOMPRESSED = 0,
DYLD_CHAINED_SYMBOL_ZLIB = 1,
};
/// Structs for dyld chained fixups.
/// dyld_chained_fixups_header is the data pointed to by LC_DYLD_CHAINED_FIXUPS
/// load command.

View File

@ -1,102 +1,106 @@
# 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
FileHeader:
magic: 0xFEEDFACF
cputype: 0x100000C
cpusubtype: 0x0
filetype: 0x2
ncmds: 16
sizeofcmds: 744
flags: 0x200085
cputype: 0x1000007
cpusubtype: 0x3
filetype: 0x6
ncmds: 13
sizeofcmds: 568
flags: 0x100085
reserved: 0x0
LoadCommands:
- cmd: LC_SEGMENT_64
cmdsize: 72
segname: __PAGEZERO
vmaddr: 0
vmsize: 4294967296
fileoff: 0
filesize: 0
maxprot: 0
initprot: 0
nsects: 0
flags: 0
- cmd: LC_SEGMENT_64
cmdsize: 232
cmdsize: 152
segname: __TEXT
vmaddr: 4294967296
vmaddr: 0
vmsize: 16384
fileoff: 0
filesize: 16384
maxprot: 5
initprot: 5
nsects: 2
nsects: 1
flags: 0
Sections:
- sectname: __text
segname: __TEXT
addr: 0x100003F98
size: 24
offset: 0x3F98
align: 2
addr: 0x4000
size: 0
offset: 0x4000
align: 0
reloff: 0x0
nreloc: 0
flags: 0x80000400
reserved1: 0x0
reserved2: 0x0
reserved3: 0x0
content: C0035FD6FF4300D100008052FF0F00B9FF430091C0035FD6
- sectname: __unwind_info
segname: __TEXT
addr: 0x100003FB0
size: 80
offset: 0x3FB0
align: 2
reloff: 0x0
nreloc: 0
flags: 0x0
reserved1: 0x0
reserved2: 0x0
reserved3: 0x0
content: 010000001C000000000000001C000000000000001C00000002000000983F00003400000034000000B13F00000000000034000000030000000C0002001400020000000001040000000010000200000002
content: ''
- cmd: LC_SEGMENT_64
cmdsize: 72
segname: __LINKEDIT
vmaddr: 4294983680
vmaddr: 16384
vmsize: 16384
fileoff: 16384
filesize: 753
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: 56
datasize: 48
- cmd: LC_DYLD_EXPORTS_TRIE
cmdsize: 16
dataoff: 16440
datasize: 56
dataoff: 16432
datasize: 16
- cmd: LC_SYMTAB
cmdsize: 24
symoff: 16504
nsyms: 15
stroff: 16744
strsize: 120
symoff: 16456
nsyms: 1
stroff: 16472
strsize: 8
- cmd: LC_DYSYMTAB
cmdsize: 80
ilocalsym: 0
nlocalsym: 12
iextdefsym: 12
nextdefsym: 3
iundefsym: 15
nlocalsym: 0
iextdefsym: 0
nextdefsym: 1
iundefsym: 1
nundefsym: 0
tocoff: 0
ntoc: 0
@ -110,136 +114,37 @@ LoadCommands:
nextrel: 0
locreloff: 0
nlocrel: 0
- cmd: LC_LOAD_DYLINKER
cmdsize: 32
name: 12
Content: '/usr/lib/dyld'
ZeroPadBytes: 7
- cmd: LC_UUID
cmdsize: 24
uuid: F445529E-643C-3A38-8F59-AB64566BCAFF
uuid: 52409B91-DF59-346A-A63F-D4E6FFDC3E04
- cmd: LC_BUILD_VERSION
cmdsize: 32
platform: 1
minos: 786432
sdk: 786432
sdk: 851968
ntools: 1
Tools:
- tool: 3
version: 46596096
version: 53674242
- cmd: LC_SOURCE_VERSION
cmdsize: 16
version: 0
- cmd: LC_MAIN
cmdsize: 24
entryoff: 16284
stacksize: 0
- cmd: LC_LOAD_DYLIB
cmdsize: 56
dylib:
name: 24
timestamp: 2
current_version: 85917696
current_version: 65793
compatibility_version: 65536
Content: '/usr/lib/libSystem.B.dylib'
ZeroPadBytes: 6
Content: '/usr/lib/libSystem.dylib'
ZeroPadBytes: 8
- cmd: LC_FUNCTION_STARTS
cmdsize: 16
dataoff: 16496
dataoff: 16448
datasize: 8
- cmd: LC_DATA_IN_CODE
cmdsize: 16
dataoff: 16504
dataoff: 16456
datasize: 0
- cmd: LC_CODE_SIGNATURE
cmdsize: 16
dataoff: 16864
datasize: 273
LinkEditData:
NameList:
- n_strx: 33
n_type: 0x64
n_sect: 0
n_desc: 0
n_value: 0
- n_strx: 39
n_type: 0x64
n_sect: 0
n_desc: 0
n_value: 0
- n_strx: 46
n_type: 0x66
n_sect: 0
n_desc: 1
n_value: 1636754403
- n_strx: 1
n_type: 0x2E
n_sect: 1
n_desc: 0
n_value: 4294983576
- n_strx: 109
n_type: 0x24
n_sect: 1
n_desc: 0
n_value: 4294983576
- n_strx: 1
n_type: 0x24
n_sect: 0
n_desc: 0
n_value: 4
- n_strx: 1
n_type: 0x4E
n_sect: 1
n_desc: 0
n_value: 4
- n_strx: 1
n_type: 0x2E
n_sect: 1
n_desc: 0
n_value: 4294983580
- n_strx: 114
n_type: 0x24
n_sect: 1
n_desc: 0
n_value: 4294983580
- n_strx: 1
n_type: 0x24
n_sect: 0
n_desc: 0
n_value: 20
- n_strx: 1
n_type: 0x4E
n_sect: 1
n_desc: 0
n_value: 20
- n_strx: 1
n_type: 0x64
n_sect: 1
n_desc: 0
n_value: 0
- n_strx: 2
n_type: 0xF
n_sect: 1
n_desc: 16
n_value: 4294967296
- n_strx: 22
n_type: 0xF
n_sect: 1
n_desc: 0
n_value: 4294983576
- n_strx: 27
n_type: 0xF
n_sect: 1
n_desc: 0
n_value: 4294983580
StringTable:
- ' '
- __mh_execute_header
- _foo
- _main
- '/tmp/'
- main.c
- '/var/folders/gj/wf3swl0x215b2sq1qy84kzkm0000gn/T/main-e32fe7.o'
- _foo
- _main
__LINKEDIT: 00000000200000002C0000002C000000000000000100000000000000000000000200000000000000000000000000000000015F666F6F000804008080010000000000000000000000020000000F010000004000000000000020005F666F6F0000
...

View File

@ -81,6 +81,7 @@ bool objdump::DataInCode;
bool objdump::FunctionStarts;
bool objdump::LinkOptHints;
bool objdump::InfoPlist;
bool objdump::ChainedFixups;
bool objdump::DyldInfo;
bool objdump::DylibsUsed;
bool objdump::DylibId;
@ -112,6 +113,7 @@ void objdump::parseMachOOptions(const llvm::opt::InputArgList &InputArgs) {
FunctionStarts = InputArgs.hasArg(OBJDUMP_function_starts);
LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints);
InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist);
ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups);
DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info);
DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used);
DylibId = InputArgs.hasArg(OBJDUMP_dylib_id);
@ -1193,6 +1195,48 @@ static void printMachOChainedFixups(object::MachOObjectFile *Obj) {
reportError(std::move(Err), Obj->getFileName());
}
static void
PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) {
outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n";
outs() << " fixups_version = " << H.fixups_version << '\n';
outs() << " starts_offset = " << H.starts_offset << '\n';
outs() << " imports_offset = " << H.imports_offset << '\n';
outs() << " symbols_offset = " << H.symbols_offset << '\n';
outs() << " imports_count = " << H.imports_count << '\n';
outs() << " imports_format = " << H.imports_format;
switch (H.imports_format) {
case llvm::MachO::DYLD_CHAINED_IMPORT:
outs() << " (DYLD_CHAINED_IMPORT)";
break;
case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND:
outs() << " (DYLD_CHAINED_IMPORT_ADDEND)";
break;
case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64:
outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)";
break;
}
outs() << '\n';
outs() << " symbols_format = " << H.symbols_format;
if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB)
outs() << " (zlib compressed)";
outs() << '\n';
}
static void PrintChainedFixups(MachOObjectFile *O) {
// MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS.
// FIXME: Support chained fixups in __TEXT,__chain_starts section too.
auto ChainedFixupHeader =
unwrapOrError(O->getChainedFixupsHeader(), O->getFileName());
if (!ChainedFixupHeader)
return;
PrintChainedFixupsHeader(*ChainedFixupHeader);
// FIXME: Print more things.
}
static void PrintDyldInfo(MachOObjectFile *O) {
outs() << "dyld information:" << '\n';
printMachOChainedFixups(O);
@ -1916,8 +1960,9 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase ||
Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols ||
DataInCode || FunctionStarts || LinkOptHints || DyldInfo || DylibsUsed ||
DylibId || Rpaths || ObjcMetaData || (!FilterSections.empty())) {
DataInCode || FunctionStarts || LinkOptHints || ChainedFixups ||
DyldInfo || DylibsUsed || DylibId || Rpaths || ObjcMetaData ||
(!FilterSections.empty())) {
if (LeadingHeaders) {
outs() << Name;
if (!ArchiveMemberName.empty())
@ -1986,6 +2031,8 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
DumpSectionContents(FileName, MachOOF, Verbose);
if (InfoPlist)
DumpInfoPlistSectionContents(FileName, MachOOF);
if (ChainedFixups)
PrintChainedFixups(MachOOF);
if (DyldInfo)
PrintDyldInfo(MachOOF);
if (DylibsUsed)

View File

@ -36,6 +36,7 @@ void parseMachOOptions(const llvm::opt::InputArgList &InputArgs);
extern bool Bind;
extern bool DataInCode;
extern std::string DisSymName;
extern bool ChainedFixups;
extern bool DyldInfo;
extern bool DylibId;
extern bool DylibsUsed;

View File

@ -299,11 +299,15 @@ def info_plist : Flag<["--"], "info-plist">,
"Mach-O objects (requires --macho)">,
Group<grp_mach_o>;
def chained_fixups : Flag<["--"], "chained-fixups">,
HelpText<"Print chained fixup information (requires --macho)">,
Group<grp_mach_o>;
def dyld_info : Flag<["--"], "dyld_info">,
HelpText<"Print bind and rebase information used by dyld to resolve "
"external references in a final linked binary "
"(requires --macho)">,
Group<grp_mach_o>;
HelpText<"Print bind and rebase information used by dyld to resolve "
"external references in a final linked binary "
"(requires --macho)">,
Group<grp_mach_o>;
def dylibs_used : Flag<["--"], "dylibs-used">,
HelpText<"Print the shared libraries used for linked "

View File

@ -37,13 +37,15 @@ def V : Flag<["-"], "V">,
def x : Flag<["-"], "x">, HelpText<"print all text sections">;
def X : Flag<["-"], "X">, HelpText<"omit leading addresses or headers">;
def chained_fixups : Flag<["-"], "chained_fixups">,
HelpText<"print chained fixup information">;
// Not (yet?) implemented:
// def a : Flag<["-"], "a">, HelpText<"print archive header">;
// -c print argument strings of a core file
// -m don't use archive(member) syntax
// -dyld_info
// -dyld_opcodes
// -chained_fixups
// -addr_slide=arg
// -function_offsets

View File

@ -2787,6 +2787,8 @@ static void parseOtoolOptions(const llvm::opt::InputArgList &InputArgs) {
FilterSections.push_back(",__text");
LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X);
ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups);
InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT);
if (InputFilenames.empty())
reportCmdLineError("no input file");
@ -2990,11 +2992,12 @@ int main(int argc, char **argv) {
!DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST &&
!Relocations && !SectionHeaders && !SectionContents && !SymbolTable &&
!DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading &&
!(MachOOpt && (Bind || DataInCode || DyldInfo || DylibId || DylibsUsed ||
ExportsTrie || FirstPrivateHeader || FunctionStarts ||
IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
ObjcMetaData || Rebase || Rpaths || UniversalHeaders ||
WeakBind || !FilterSections.empty()))) {
!(MachOOpt &&
(Bind || DataInCode || ChainedFixups || DyldInfo || DylibId ||
DylibsUsed || ExportsTrie || FirstPrivateHeader || FunctionStarts ||
IndirectSymbols || InfoPlist || LazyBind || LinkOptHints ||
ObjcMetaData || Rebase || Rpaths || UniversalHeaders || WeakBind ||
!FilterSections.empty()))) {
T->printHelp(ToolName);
return 2;
}