From d88a2907afe89c7b92674b01bf6a1fdd03e1a294 Mon Sep 17 00:00:00 2001 From: Philip Craig Date: Tue, 24 Oct 2023 14:47:05 +1000 Subject: [PATCH] macho: add some objcopy tests Currently only x86-64 and AArch64 work. i386 and ARM are missing support for scattered relocations and paired relocations. Also add support for an environment called OBJECT_TESTFILES_UPDATE which causes the tests to update the output files. --- crates/examples/Cargo.toml | 5 +- crates/examples/src/bin/objcopy.rs | 164 +---------- crates/examples/src/lib.rs | 3 + crates/examples/src/objcopy.rs | 165 +++++++++++ .../testfiles/macho/base-aarch64.o.objcopy | 164 +++++++++++ .../testfiles/macho/base-x86_64.o.objcopy | 140 +++++++++ .../testfiles/macho/reloc-aarch64.o.objcopy | 271 ++++++++++++++++++ .../testfiles/macho/reloc-x86_64.o.objcopy | 201 +++++++++++++ crates/examples/tests/testfiles.rs | 26 +- 9 files changed, 972 insertions(+), 167 deletions(-) create mode 100644 crates/examples/src/objcopy.rs create mode 100644 crates/examples/testfiles/macho/base-aarch64.o.objcopy create mode 100644 crates/examples/testfiles/macho/base-x86_64.o.objcopy create mode 100644 crates/examples/testfiles/macho/reloc-aarch64.o.objcopy create mode 100644 crates/examples/testfiles/macho/reloc-x86_64.o.objcopy diff --git a/crates/examples/Cargo.toml b/crates/examples/Cargo.toml index af320f12..cca7dc81 100644 --- a/crates/examples/Cargo.toml +++ b/crates/examples/Cargo.toml @@ -12,9 +12,10 @@ glob = "0.3" [features] read = ["object/read"] +write = ["object/write"] wasm = ["object/wasm"] xcoff = ["object/xcoff"] -all = ["read", "wasm", "xcoff"] +all = ["read", "write", "wasm", "xcoff"] unstable-all = ["all"] default = ["read"] @@ -36,7 +37,7 @@ required-features = ["object/read_core", "object/write_core", "object/elf", "obj [[bin]] name = "objcopy" -required-features = ["object/read", "object/write"] +required-features = ["read", "write"] [[bin]] name = "objdump" diff --git a/crates/examples/src/bin/objcopy.rs b/crates/examples/src/bin/objcopy.rs index 4b8b0b90..5746bff4 100644 --- a/crates/examples/src/bin/objcopy.rs +++ b/crates/examples/src/bin/objcopy.rs @@ -1,10 +1,6 @@ -use std::collections::HashMap; -use std::{env, fs, process}; +use object_examples::objcopy; -use object::{ - write, Object, ObjectComdat, ObjectKind, ObjectSection, ObjectSymbol, RelocationTarget, - SectionKind, SymbolFlags, SymbolKind, SymbolSection, -}; +use std::{env, fs, process}; fn main() { let mut args = env::args(); @@ -24,168 +20,16 @@ fn main() { process::exit(1); } }; - let in_file = match unsafe { memmap2::Mmap::map(&in_file) } { + let in_data = match unsafe { memmap2::Mmap::map(&in_file) } { Ok(mmap) => mmap, Err(err) => { eprintln!("Failed to map file '{}': {}", in_file_path, err,); process::exit(1); } }; - let in_object = match object::File::parse(&*in_file) { - Ok(object) => object, - Err(err) => { - eprintln!("Failed to parse file '{}': {}", in_file_path, err); - process::exit(1); - } - }; - if in_object.kind() != ObjectKind::Relocatable { - eprintln!("Unsupported object kind: {:?}", in_object.kind()); - process::exit(1); - } - - let mut out_object = write::Object::new( - in_object.format(), - in_object.architecture(), - in_object.endianness(), - ); - out_object.mangling = write::Mangling::None; - out_object.flags = in_object.flags(); - - let mut out_sections = HashMap::new(); - for in_section in in_object.sections() { - if in_section.kind() == SectionKind::Metadata { - continue; - } - let section_id = out_object.add_section( - in_section - .segment_name() - .unwrap() - .unwrap_or("") - .as_bytes() - .to_vec(), - in_section.name().unwrap().as_bytes().to_vec(), - in_section.kind(), - ); - let out_section = out_object.section_mut(section_id); - if out_section.is_bss() { - out_section.append_bss(in_section.size(), in_section.align()); - } else { - out_section.set_data(in_section.data().unwrap(), in_section.align()); - } - out_section.flags = in_section.flags(); - out_sections.insert(in_section.index(), section_id); - } - - let mut out_symbols = HashMap::new(); - for in_symbol in in_object.symbols() { - if in_symbol.kind() == SymbolKind::Null { - continue; - } - let (section, value) = match in_symbol.section() { - SymbolSection::None => (write::SymbolSection::None, in_symbol.address()), - SymbolSection::Undefined => (write::SymbolSection::Undefined, in_symbol.address()), - SymbolSection::Absolute => (write::SymbolSection::Absolute, in_symbol.address()), - SymbolSection::Common => (write::SymbolSection::Common, in_symbol.address()), - SymbolSection::Section(index) => { - if let Some(out_section) = out_sections.get(&index) { - ( - write::SymbolSection::Section(*out_section), - in_symbol.address() - in_object.section_by_index(index).unwrap().address(), - ) - } else { - // Ignore symbols for sections that we have skipped. - assert_eq!(in_symbol.kind(), SymbolKind::Section); - continue; - } - } - _ => panic!("unknown symbol section for {:?}", in_symbol), - }; - let flags = match in_symbol.flags() { - SymbolFlags::None => SymbolFlags::None, - SymbolFlags::Elf { st_info, st_other } => SymbolFlags::Elf { st_info, st_other }, - SymbolFlags::MachO { n_desc } => SymbolFlags::MachO { n_desc }, - SymbolFlags::CoffSection { - selection, - associative_section, - } => { - let associative_section = - associative_section.map(|index| *out_sections.get(&index).unwrap()); - SymbolFlags::CoffSection { - selection, - associative_section, - } - } - SymbolFlags::Xcoff { - n_sclass, - x_smtyp, - x_smclas, - containing_csect, - } => { - let containing_csect = - containing_csect.map(|index| *out_symbols.get(&index).unwrap()); - SymbolFlags::Xcoff { - n_sclass, - x_smtyp, - x_smclas, - containing_csect, - } - } - _ => panic!("unknown symbol flags for {:?}", in_symbol), - }; - let out_symbol = write::Symbol { - name: in_symbol.name().unwrap_or("").as_bytes().to_vec(), - value, - size: in_symbol.size(), - kind: in_symbol.kind(), - scope: in_symbol.scope(), - weak: in_symbol.is_weak(), - section, - flags, - }; - let symbol_id = out_object.add_symbol(out_symbol); - out_symbols.insert(in_symbol.index(), symbol_id); - } - for in_section in in_object.sections() { - if in_section.kind() == SectionKind::Metadata { - continue; - } - let out_section = *out_sections.get(&in_section.index()).unwrap(); - for (offset, in_relocation) in in_section.relocations() { - let symbol = match in_relocation.target() { - RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(), - RelocationTarget::Section(section) => { - out_object.section_symbol(*out_sections.get(§ion).unwrap()) - } - _ => panic!("unknown relocation target for {:?}", in_relocation), - }; - let out_relocation = write::Relocation { - offset, - size: in_relocation.size(), - kind: in_relocation.kind(), - encoding: in_relocation.encoding(), - symbol, - addend: in_relocation.addend(), - }; - out_object - .add_relocation(out_section, out_relocation) - .unwrap(); - } - } - - for in_comdat in in_object.comdats() { - let mut sections = Vec::new(); - for in_section in in_comdat.sections() { - sections.push(*out_sections.get(&in_section).unwrap()); - } - out_object.add_comdat(write::Comdat { - kind: in_comdat.kind(), - symbol: *out_symbols.get(&in_comdat.symbol()).unwrap(), - sections, - }); - } + let out_data = objcopy::copy(&in_data); - let out_data = out_object.write().unwrap(); if let Err(err) = fs::write(&out_file_path, out_data) { eprintln!("Failed to write file '{}': {}", out_file_path, err); process::exit(1); diff --git a/crates/examples/src/lib.rs b/crates/examples/src/lib.rs index 31a14193..c17c6e36 100644 --- a/crates/examples/src/lib.rs +++ b/crates/examples/src/lib.rs @@ -1,6 +1,9 @@ // Style. #![allow(clippy::single_match)] +#[cfg(all(feature = "read", feature = "write"))] +pub mod objcopy; + #[cfg(feature = "read")] pub mod objdump; diff --git a/crates/examples/src/objcopy.rs b/crates/examples/src/objcopy.rs new file mode 100644 index 00000000..3dda5d20 --- /dev/null +++ b/crates/examples/src/objcopy.rs @@ -0,0 +1,165 @@ +use std::collections::HashMap; +use std::process; + +use object::{ + write, Object, ObjectComdat, ObjectKind, ObjectSection, ObjectSymbol, RelocationTarget, + SectionKind, SymbolFlags, SymbolKind, SymbolSection, +}; + +pub fn copy(in_data: &[u8]) -> Vec { + let in_object = match object::File::parse(in_data) { + Ok(object) => object, + Err(err) => { + eprintln!("Failed to parse file: {}", err); + process::exit(1); + } + }; + if in_object.kind() != ObjectKind::Relocatable { + eprintln!("Unsupported object kind: {:?}", in_object.kind()); + process::exit(1); + } + + let mut out_object = write::Object::new( + in_object.format(), + in_object.architecture(), + in_object.endianness(), + ); + out_object.mangling = write::Mangling::None; + out_object.flags = in_object.flags(); + + let mut out_sections = HashMap::new(); + for in_section in in_object.sections() { + if in_section.kind() == SectionKind::Metadata { + continue; + } + let section_id = out_object.add_section( + in_section + .segment_name() + .unwrap() + .unwrap_or("") + .as_bytes() + .to_vec(), + in_section.name().unwrap().as_bytes().to_vec(), + in_section.kind(), + ); + let out_section = out_object.section_mut(section_id); + if out_section.is_bss() { + out_section.append_bss(in_section.size(), in_section.align()); + } else { + out_section.set_data(in_section.data().unwrap(), in_section.align()); + } + out_section.flags = in_section.flags(); + out_sections.insert(in_section.index(), section_id); + } + + let mut out_symbols = HashMap::new(); + for in_symbol in in_object.symbols() { + if in_symbol.kind() == SymbolKind::Null { + continue; + } + let (section, value) = match in_symbol.section() { + SymbolSection::None => (write::SymbolSection::None, in_symbol.address()), + SymbolSection::Undefined => (write::SymbolSection::Undefined, in_symbol.address()), + SymbolSection::Absolute => (write::SymbolSection::Absolute, in_symbol.address()), + SymbolSection::Common => (write::SymbolSection::Common, in_symbol.address()), + SymbolSection::Section(index) => { + if let Some(out_section) = out_sections.get(&index) { + ( + write::SymbolSection::Section(*out_section), + in_symbol.address() - in_object.section_by_index(index).unwrap().address(), + ) + } else { + // Ignore symbols for sections that we have skipped. + assert_eq!(in_symbol.kind(), SymbolKind::Section); + continue; + } + } + _ => panic!("unknown symbol section for {:?}", in_symbol), + }; + let flags = match in_symbol.flags() { + SymbolFlags::None => SymbolFlags::None, + SymbolFlags::Elf { st_info, st_other } => SymbolFlags::Elf { st_info, st_other }, + SymbolFlags::MachO { n_desc } => SymbolFlags::MachO { n_desc }, + SymbolFlags::CoffSection { + selection, + associative_section, + } => { + let associative_section = + associative_section.map(|index| *out_sections.get(&index).unwrap()); + SymbolFlags::CoffSection { + selection, + associative_section, + } + } + SymbolFlags::Xcoff { + n_sclass, + x_smtyp, + x_smclas, + containing_csect, + } => { + let containing_csect = + containing_csect.map(|index| *out_symbols.get(&index).unwrap()); + SymbolFlags::Xcoff { + n_sclass, + x_smtyp, + x_smclas, + containing_csect, + } + } + _ => panic!("unknown symbol flags for {:?}", in_symbol), + }; + let out_symbol = write::Symbol { + name: in_symbol.name().unwrap_or("").as_bytes().to_vec(), + value, + size: in_symbol.size(), + kind: in_symbol.kind(), + scope: in_symbol.scope(), + weak: in_symbol.is_weak(), + section, + flags, + }; + let symbol_id = out_object.add_symbol(out_symbol); + out_symbols.insert(in_symbol.index(), symbol_id); + } + + for in_section in in_object.sections() { + if in_section.kind() == SectionKind::Metadata { + continue; + } + let out_section = *out_sections.get(&in_section.index()).unwrap(); + for (offset, in_relocation) in in_section.relocations() { + let symbol = match in_relocation.target() { + RelocationTarget::Symbol(symbol) => *out_symbols.get(&symbol).unwrap(), + RelocationTarget::Section(section) => { + out_object.section_symbol(*out_sections.get(§ion).unwrap()) + } + _ => panic!("unknown relocation target for {:?}", in_relocation), + }; + let out_relocation = write::Relocation { + offset, + size: in_relocation.size(), + kind: in_relocation.kind(), + encoding: in_relocation.encoding(), + symbol, + addend: in_relocation.addend(), + }; + out_object + .add_relocation(out_section, out_relocation) + .unwrap(); + } + } + + for in_comdat in in_object.comdats() { + let mut sections = Vec::new(); + for in_section in in_comdat.sections() { + sections.push(*out_sections.get(&in_section).unwrap()); + } + out_object.add_comdat(write::Comdat { + kind: in_comdat.kind(), + symbol: *out_symbols.get(&in_comdat.symbol()).unwrap(), + sections, + }); + } + + out_object.write().unwrap() +} diff --git a/crates/examples/testfiles/macho/base-aarch64.o.objcopy b/crates/examples/testfiles/macho/base-aarch64.o.objcopy new file mode 100644 index 00000000..1473d57b --- /dev/null +++ b/crates/examples/testfiles/macho/base-aarch64.o.objcopy @@ -0,0 +1,164 @@ +Format: Mach-O 64-bit +MachHeader { + Magic: 0xCFFAEDFE + CpuType: CPU_TYPE_ARM64 (0x100000C) + CpuSubtype: 0x0 + CPU_SUBTYPE_ARM64_ALL (0x0) + FileType: MH_OBJECT (0x1) + NumberOfCmds: 2 + SizeOfCmds: 0x150 + Flags: MH_SUBSECTIONS_VIA_SYMBOLS (0x2000) +} +SegmentCommand { + Cmd: LC_SEGMENT_64 (0x19) + CmdSize: 0x138 + SegmentName: "" + VmAddress: 0x0 + VmSize: 0x68 + FileOffset: 0x170 + FileSize: 0x68 + MaxProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + InitProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + NumberOfSections: 3 + Flags: 0x0 + Section { + Index: 0 + SectionName: "__text" + SegmentName: "__TEXT" + Address: 0x0 + Size: 0x34 + Offset: 0x170 + Align: 0x2 + RelocationOffset: 0x260 + NumberOfRelocations: 0x3 + Flags: 0x80000400 + S_REGULAR (0x0) + S_ATTR_PURE_INSTRUCTIONS (0x80000000) + S_ATTR_SOME_INSTRUCTIONS (0x400) + RelocationInfo { + Address: 0x20 + Extern: yes + Symbol: "_printf" (0x5) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_BRANCH26 (0x2) + } + RelocationInfo { + Address: 0x1C + Extern: yes + Symbol: "l_.str" (0x1) + PcRel: no + Length: 2 + Type: ARM64_RELOC_PAGEOFF12 (0x4) + } + RelocationInfo { + Address: 0x18 + Extern: yes + Symbol: "l_.str" (0x1) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_PAGE21 (0x3) + } + } + Section { + Index: 1 + SectionName: "__cstring" + SegmentName: "__TEXT" + Address: 0x34 + Size: 0xD + Offset: 0x1A4 + Align: 0x0 + RelocationOffset: 0x0 + NumberOfRelocations: 0x0 + Flags: S_CSTRING_LITERALS (0x2) + } + Section { + Index: 2 + SectionName: "__compact_unwind" + SegmentName: "__LD" + Address: 0x48 + Size: 0x20 + Offset: 0x1B8 + Align: 0x3 + RelocationOffset: 0x278 + NumberOfRelocations: 0x1 + Flags: 0x2000000 + S_REGULAR (0x0) + S_ATTR_DEBUG (0x2000000) + RelocationInfo { + Address: 0x0 + Extern: no + Section: "__TEXT,__text" (0x1) + PcRel: no + Length: 3 + Type: ARM64_RELOC_UNSIGNED (0x0) + } + } +} +SymtabCommand { + Cmd: LC_SYMTAB (0x2) + CmdSize: 0x18 + SymbolOffset: 0x1D8 + NumberOfSymbols: 0x6 + StringOffset: 0x238 + StringSize: 0x28 + Nlist { + Index: 0 + String: "ltmp0" (0x22) + Type: N_SECT (0xE) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x0 + } + Nlist { + Index: 1 + String: "l_.str" (0x1) + Type: N_SECT (0xE) + Section: "__TEXT,__cstring" (0x2) + Desc: 0x0 + Value: 0x34 + } + Nlist { + Index: 2 + String: "ltmp1" (0x1C) + Type: N_SECT (0xE) + Section: "__TEXT,__cstring" (0x2) + Desc: 0x0 + Value: 0x34 + } + Nlist { + Index: 3 + String: "ltmp2" (0x16) + Type: N_SECT (0xE) + Section: "__LD,__compact_unwind" (0x3) + Desc: 0x0 + Value: 0x48 + } + Nlist { + Index: 4 + String: "_main" (0x8) + Type: 0xF + N_SECT (0xE) + N_EXT (0x1) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x0 + } + Nlist { + Index: 5 + String: "_printf" (0xE) + Type: 0x1 + N_UNDF (0x0) + N_EXT (0x1) + Section: "" (0x0) + Desc: 0x0 + REFERENCE_FLAG_UNDEFINED_NON_LAZY (0x0) + Value: 0x0 + } +} diff --git a/crates/examples/testfiles/macho/base-x86_64.o.objcopy b/crates/examples/testfiles/macho/base-x86_64.o.objcopy new file mode 100644 index 00000000..ee077284 --- /dev/null +++ b/crates/examples/testfiles/macho/base-x86_64.o.objcopy @@ -0,0 +1,140 @@ +Format: Mach-O 64-bit +MachHeader { + Magic: 0xCFFAEDFE + CpuType: CPU_TYPE_X86_64 (0x1000007) + CpuSubtype: 0x3 + CPU_SUBTYPE_X86_64_ALL (0x3) + FileType: MH_OBJECT (0x1) + NumberOfCmds: 2 + SizeOfCmds: 0x1A0 + Flags: MH_SUBSECTIONS_VIA_SYMBOLS (0x2000) +} +SegmentCommand { + Cmd: LC_SEGMENT_64 (0x19) + CmdSize: 0x188 + SegmentName: "" + VmAddress: 0x0 + VmSize: 0x98 + FileOffset: 0x1C0 + FileSize: 0x98 + MaxProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + InitProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + NumberOfSections: 4 + Flags: 0x0 + Section { + Index: 0 + SectionName: "__text" + SegmentName: "__TEXT" + Address: 0x0 + Size: 0x25 + Offset: 0x1C0 + Align: 0x4 + RelocationOffset: 0x288 + NumberOfRelocations: 0x2 + Flags: 0x80000400 + S_REGULAR (0x0) + S_ATTR_PURE_INSTRUCTIONS (0x80000000) + S_ATTR_SOME_INSTRUCTIONS (0x400) + RelocationInfo { + Address: 0x19 + Extern: yes + Symbol: "_printf" (0x1) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_BRANCH (0x2) + } + RelocationInfo { + Address: 0x12 + Extern: no + Section: "__TEXT,__cstring" (0x2) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED (0x1) + } + } + Section { + Index: 1 + SectionName: "__cstring" + SegmentName: "__TEXT" + Address: 0x25 + Size: 0xD + Offset: 0x1E5 + Align: 0x0 + RelocationOffset: 0x0 + NumberOfRelocations: 0x0 + Flags: S_CSTRING_LITERALS (0x2) + } + Section { + Index: 2 + SectionName: "__compact_unwind" + SegmentName: "__LD" + Address: 0x38 + Size: 0x20 + Offset: 0x1F8 + Align: 0x3 + RelocationOffset: 0x298 + NumberOfRelocations: 0x1 + Flags: 0x2000000 + S_REGULAR (0x0) + S_ATTR_DEBUG (0x2000000) + RelocationInfo { + Address: 0x0 + Extern: no + Section: "__TEXT,__text" (0x1) + PcRel: no + Length: 3 + Type: X86_64_RELOC_UNSIGNED (0x0) + } + } + Section { + Index: 3 + SectionName: "__eh_frame" + SegmentName: "__TEXT" + Address: 0x58 + Size: 0x40 + Offset: 0x218 + Align: 0x3 + RelocationOffset: 0x0 + NumberOfRelocations: 0x0 + Flags: 0x6800000B + S_COALESCED (0xB) + S_ATTR_NO_TOC (0x40000000) + S_ATTR_STRIP_STATIC_SYMS (0x20000000) + S_ATTR_LIVE_SUPPORT (0x8000000) + } +} +SymtabCommand { + Cmd: LC_SYMTAB (0x2) + CmdSize: 0x18 + SymbolOffset: 0x258 + NumberOfSymbols: 0x2 + StringOffset: 0x278 + StringSize: 0xF + Nlist { + Index: 0 + String: "_main" (0x1) + Type: 0xF + N_SECT (0xE) + N_EXT (0x1) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x0 + } + Nlist { + Index: 1 + String: "_printf" (0x7) + Type: 0x1 + N_UNDF (0x0) + N_EXT (0x1) + Section: "" (0x0) + Desc: 0x0 + REFERENCE_FLAG_UNDEFINED_NON_LAZY (0x0) + Value: 0x0 + } +} diff --git a/crates/examples/testfiles/macho/reloc-aarch64.o.objcopy b/crates/examples/testfiles/macho/reloc-aarch64.o.objcopy new file mode 100644 index 00000000..6314560c --- /dev/null +++ b/crates/examples/testfiles/macho/reloc-aarch64.o.objcopy @@ -0,0 +1,271 @@ +Format: Mach-O 64-bit +MachHeader { + Magic: 0xCFFAEDFE + CpuType: CPU_TYPE_ARM64 (0x100000C) + CpuSubtype: 0x0 + CPU_SUBTYPE_ARM64_ALL (0x0) + FileType: MH_OBJECT (0x1) + NumberOfCmds: 2 + SizeOfCmds: 0x100 + Flags: MH_SUBSECTIONS_VIA_SYMBOLS (0x2000) +} +SegmentCommand { + Cmd: LC_SEGMENT_64 (0x19) + CmdSize: 0xE8 + SegmentName: "" + VmAddress: 0x0 + VmSize: 0x48 + FileOffset: 0x120 + FileSize: 0x48 + MaxProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + InitProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + NumberOfSections: 2 + Flags: 0x0 + Section { + Index: 0 + SectionName: "__text" + SegmentName: "__TEXT" + Address: 0x0 + Size: 0x28 + Offset: 0x120 + Align: 0x0 + RelocationOffset: 0x1D4 + NumberOfRelocations: 0xD + Flags: 0x80000400 + S_REGULAR (0x0) + S_ATTR_PURE_INSTRUCTIONS (0x80000000) + S_ATTR_SOME_INSTRUCTIONS (0x400) + RelocationInfo { + Address: 0x24 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 2 + Type: ARM64_RELOC_TLVP_LOAD_PAGEOFF12 (0x9) + } + RelocationInfo { + Address: 0x20 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_TLVP_LOAD_PAGE21 (0x8) + } + RelocationInfo { + Address: 0x1C + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 2 + Type: ARM64_RELOC_GOT_LOAD_PAGEOFF12 (0x6) + } + RelocationInfo { + Address: 0x18 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_GOT_LOAD_PAGE21 (0x5) + } + RelocationInfo { + Address: 0x14 + Extern: no + Section: 0x14 + PcRel: no + Length: 2 + Type: ARM64_RELOC_ADDEND (0xA) + } + RelocationInfo { + Address: 0x14 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 2 + Type: ARM64_RELOC_PAGEOFF12 (0x4) + } + RelocationInfo { + Address: 0x10 + Extern: no + Section: 0x14 + PcRel: no + Length: 2 + Type: ARM64_RELOC_ADDEND (0xA) + } + RelocationInfo { + Address: 0x10 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_PAGE21 (0x3) + } + RelocationInfo { + Address: 0xC + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 2 + Type: ARM64_RELOC_PAGEOFF12 (0x4) + } + RelocationInfo { + Address: 0x8 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_PAGE21 (0x3) + } + RelocationInfo { + Address: 0x4 + Extern: no + Section: 0x14 + PcRel: no + Length: 2 + Type: ARM64_RELOC_ADDEND (0xA) + } + RelocationInfo { + Address: 0x4 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_BRANCH26 (0x2) + } + RelocationInfo { + Address: 0x0 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_BRANCH26 (0x2) + } + } + Section { + Index: 1 + SectionName: "__data" + SegmentName: "__DATA" + Address: 0x28 + Size: 0x20 + Offset: 0x148 + Align: 0x0 + RelocationOffset: 0x23C + NumberOfRelocations: 0x7 + Flags: S_REGULAR (0x0) + RelocationInfo { + Address: 0x1C + Extern: yes + Symbol: "_g0" (0x3) + PcRel: yes + Length: 2 + Type: ARM64_RELOC_POINTER_TO_GOT (0x7) + } + RelocationInfo { + Address: 0x14 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 3 + Type: ARM64_RELOC_POINTER_TO_GOT (0x7) + } + RelocationInfo { + Address: 0x10 + Extern: yes + Symbol: "_g1" (0x4) + PcRel: no + Length: 2 + Type: ARM64_RELOC_SUBTRACTOR (0x1) + } + RelocationInfo { + Address: 0x10 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 2 + Type: ARM64_RELOC_UNSIGNED (0x0) + } + RelocationInfo { + Address: 0x8 + Extern: yes + Symbol: "_g1" (0x4) + PcRel: no + Length: 3 + Type: ARM64_RELOC_SUBTRACTOR (0x1) + } + RelocationInfo { + Address: 0x8 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 3 + Type: ARM64_RELOC_UNSIGNED (0x0) + } + RelocationInfo { + Address: 0x0 + Extern: yes + Symbol: "_g0" (0x3) + PcRel: no + Length: 3 + Type: ARM64_RELOC_UNSIGNED (0x0) + } + } +} +SymtabCommand { + Cmd: LC_SYMTAB (0x2) + CmdSize: 0x18 + SymbolOffset: 0x168 + NumberOfSymbols: 0x5 + StringOffset: 0x1B8 + StringSize: 0x1B + Nlist { + Index: 0 + String: "ltmp0" (0x11) + Type: N_SECT (0xE) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x0 + } + Nlist { + Index: 1 + String: "ltmp1" (0x7) + Type: N_SECT (0xE) + Section: "__DATA,__data" (0x2) + Desc: 0x0 + Value: 0x28 + } + Nlist { + Index: 2 + String: "_data" (0x1) + Type: N_SECT (0xE) + Section: "__DATA,__data" (0x2) + Desc: 0x0 + Value: 0x28 + } + Nlist { + Index: 3 + String: "_g0" (0x17) + Type: 0x1 + N_UNDF (0x0) + N_EXT (0x1) + Section: "" (0x0) + Desc: 0x0 + REFERENCE_FLAG_UNDEFINED_NON_LAZY (0x0) + Value: 0x0 + } + Nlist { + Index: 4 + String: "_g1" (0xD) + Type: 0x1 + N_UNDF (0x0) + N_EXT (0x1) + Section: "" (0x0) + Desc: 0x0 + REFERENCE_FLAG_UNDEFINED_NON_LAZY (0x0) + Value: 0x0 + } +} diff --git a/crates/examples/testfiles/macho/reloc-x86_64.o.objcopy b/crates/examples/testfiles/macho/reloc-x86_64.o.objcopy new file mode 100644 index 00000000..e9d2d5f3 --- /dev/null +++ b/crates/examples/testfiles/macho/reloc-x86_64.o.objcopy @@ -0,0 +1,201 @@ +Format: Mach-O 64-bit +MachHeader { + Magic: 0xCFFAEDFE + CpuType: CPU_TYPE_X86_64 (0x1000007) + CpuSubtype: 0x3 + CPU_SUBTYPE_X86_64_ALL (0x3) + FileType: MH_OBJECT (0x1) + NumberOfCmds: 2 + SizeOfCmds: 0x100 + Flags: 0x0 +} +SegmentCommand { + Cmd: LC_SEGMENT_64 (0x19) + CmdSize: 0xE8 + SegmentName: "" + VmAddress: 0x0 + VmSize: 0x6B + FileOffset: 0x120 + FileSize: 0x6B + MaxProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + InitProt: 0x7 + VM_PROT_READ (0x1) + VM_PROT_WRITE (0x2) + VM_PROT_EXECUTE (0x4) + NumberOfSections: 2 + Flags: 0x0 + Section { + Index: 0 + SectionName: "__text" + SegmentName: "__TEXT" + Address: 0x0 + Size: 0x53 + Offset: 0x120 + Align: 0x0 + RelocationOffset: 0x1BC + NumberOfRelocations: 0xB + Flags: 0x80000400 + S_REGULAR (0x0) + S_ATTR_PURE_INSTRUCTIONS (0x80000000) + S_ATTR_SOME_INSTRUCTIONS (0x400) + RelocationInfo { + Address: 0x4F + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_TLV (0x9) + } + RelocationInfo { + Address: 0x48 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_GOT (0x4) + } + RelocationInfo { + Address: 0x42 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_GOT_LOAD (0x3) + } + RelocationInfo { + Address: 0x37 + Extern: no + Section: "__DATA,__data" (0x2) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_4 (0x8) + } + RelocationInfo { + Address: 0x2F + Extern: no + Section: "__DATA,__data" (0x2) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_2 (0x7) + } + RelocationInfo { + Address: 0x27 + Extern: no + Section: "__DATA,__data" (0x2) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_1 (0x6) + } + RelocationInfo { + Address: 0x1D + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_4 (0x8) + } + RelocationInfo { + Address: 0x15 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_2 (0x7) + } + RelocationInfo { + Address: 0xD + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED_1 (0x6) + } + RelocationInfo { + Address: 0x7 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_SIGNED (0x1) + } + RelocationInfo { + Address: 0x1 + Extern: yes + Symbol: "_g2" (0x1) + PcRel: yes + Length: 2 + Type: X86_64_RELOC_BRANCH (0x2) + } + } + Section { + Index: 1 + SectionName: "__data" + SegmentName: "__DATA" + Address: 0x53 + Size: 0x18 + Offset: 0x173 + Align: 0x0 + RelocationOffset: 0x214 + NumberOfRelocations: 0x4 + Flags: S_REGULAR (0x0) + RelocationInfo { + Address: 0x10 + Extern: yes + Symbol: "_g2" (0x1) + PcRel: no + Length: 3 + Type: X86_64_RELOC_SUBTRACTOR (0x5) + } + RelocationInfo { + Address: 0x10 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: no + Length: 3 + Type: X86_64_RELOC_UNSIGNED (0x0) + } + RelocationInfo { + Address: 0x8 + Extern: no + Section: "__DATA,__data" (0x2) + PcRel: no + Length: 3 + Type: X86_64_RELOC_UNSIGNED (0x0) + } + RelocationInfo { + Address: 0x0 + Extern: yes + Symbol: "_g1" (0x0) + PcRel: no + Length: 3 + Type: X86_64_RELOC_UNSIGNED (0x0) + } + } +} +SymtabCommand { + Cmd: LC_SYMTAB (0x2) + CmdSize: 0x18 + SymbolOffset: 0x190 + NumberOfSymbols: 0x2 + StringOffset: 0x1B0 + StringSize: 0x9 + Nlist { + Index: 0 + String: "_g1" (0x5) + Type: N_SECT (0xE) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x0 + } + Nlist { + Index: 1 + String: "_g2" (0x1) + Type: N_SECT (0xE) + Section: "__TEXT,__text" (0x1) + Desc: 0x0 + Value: 0x5 + } +} diff --git a/crates/examples/tests/testfiles.rs b/crates/examples/tests/testfiles.rs index fc105452..fcae8df5 100644 --- a/crates/examples/tests/testfiles.rs +++ b/crates/examples/tests/testfiles.rs @@ -1,5 +1,7 @@ #![cfg(feature = "read")] +#[cfg(feature = "write")] +use object_examples::objcopy; use object_examples::{objdump, readobj}; use std::ffi::OsStr; use std::io::Write; @@ -22,6 +24,8 @@ fn test_dir_filter(path: &PathBuf) -> bool { #[test] fn testfiles() { + let update = env::var_os("OBJECT_TESTFILES_UPDATE").is_some(); + // Move from crates/examples to the workspace root. env::set_current_dir("../..").unwrap(); @@ -47,17 +51,25 @@ fn testfiles() { println!("File {}", path); let data = fs::read(&path).unwrap(); - fail |= testfile(path, &data, "objdump", |mut out, mut err, data| { + fail |= testfile(update, path, &data, "objdump", |mut out, mut err, data| { objdump::print(&mut out, &mut err, data, &[], vec![]).unwrap() }); - fail |= testfile(path, &data, "readobj", readobj::print); + fail |= testfile(update, path, &data, "readobj", readobj::print); + + #[cfg(feature = "write")] + { + fail |= testfile(update, path, &data, "objcopy", |out, err, in_data| { + let out_data = objcopy::copy(in_data); + readobj::print(out, err, &out_data) + }); + } println!(); } } assert!(!fail); } -fn testfile(path: &str, data: &[u8], ext: &str, f: F) -> bool +fn testfile(update: bool, path: &str, data: &[u8], ext: &str, f: F) -> bool where F: FnOnce(&mut dyn Write, &mut dyn Write, &[u8]), { @@ -79,7 +91,9 @@ where let out_path = &format!("crates/examples/{}.{}", path, ext); if let Ok(expect_out) = fs::read(out_path) { println!("Test {}", out_path); - if out != expect_out { + if update { + fs::write(out_path, &out).unwrap(); + } else if out != expect_out { println!("FAIL mismatch"); fail = true; } @@ -102,7 +116,9 @@ where let err_path = &format!("{}.err", out_path); if let Ok(expect_err) = fs::read(err_path) { println!("Test {}", err_path); - if err != expect_err { + if update { + fs::write(err_path, &err).unwrap(); + } else if err != expect_err { println!("FAIL mismatch"); fail = true; }