Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macho: add some objcopy tests #583

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -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"
Expand Down
164 changes: 4 additions & 160 deletions crates/examples/src/bin/objcopy.rs
Original file line number Diff line number Diff line change
@@ -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();
Expand All @@ -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(&section).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);
Expand Down
3 changes: 3 additions & 0 deletions crates/examples/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Style.
#![allow(clippy::single_match)]

#[cfg(all(feature = "read", feature = "write"))]
pub mod objcopy;

#[cfg(feature = "read")]
pub mod objdump;

Expand Down
165 changes: 165 additions & 0 deletions crates/examples/src/objcopy.rs
Original file line number Diff line number Diff line change
@@ -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<u8> {
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(&section).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()
}
Loading