Write .splitmeta section in split objects

This enables showing the original address of
symbols in objdiff, as well as `elf disasm`
on split objects retaining the original
addresses.
This commit is contained in:
Luke Street 2024-02-28 22:27:38 -07:00
parent a2cae4f82a
commit 4f8a9e6fab
14 changed files with 365 additions and 84 deletions

206
Cargo.lock generated
View File

@ -49,9 +49,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.75"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
dependencies = [
"backtrace",
]
@ -80,7 +80,7 @@ dependencies = [
"argh_shared",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
@ -187,6 +187,16 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "byteorder"
version = "1.5.0"
@ -320,6 +330,7 @@ dependencies = [
"multimap",
"nintendo-lz",
"num_enum",
"objdiff-core",
"object",
"once_cell",
"owo-colors",
@ -397,14 +408,14 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.22"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"windows-sys 0.48.0",
"windows-sys 0.52.0",
]
[[package]]
@ -469,6 +480,20 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata 0.4.3",
"regex-syntax 0.8.2",
"serde",
]
[[package]]
name = "hashbrown"
version = "0.14.2"
@ -507,9 +532,9 @@ checksum = "d9f1a0777d972970f204fdf8ef319f1f4f8459131636d7e3c96c5d59570d0fa6"
[[package]]
name = "indexmap"
version = "2.1.0"
version = "2.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
checksum = "967d6dd42f16dbf0eb8040cb9e477933562684d3918f7d253f2ff9087fb3e7a3"
dependencies = [
"equivalent",
"hashbrown",
@ -555,9 +580,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.150"
version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "linux-raw-sys"
@ -588,9 +613,9 @@ checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memmap2"
version = "0.9.0"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "deaba38d7abf1d4cca21cc89e932e542ba2b9258664d2a9ef0e61512039c9375"
checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
dependencies = [
"libc",
]
@ -644,9 +669,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.17"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
@ -669,14 +694,37 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
name = "objdiff-core"
version = "1.0.0"
source = "git+https://github.com/encounter/objdiff?rev=5b9ac93c084bd0a9ae710e8c8195c4b0db939b8a#5b9ac93c084bd0a9ae710e8c8195c4b0db939b8a"
dependencies = [
"anyhow",
"byteorder",
"cwdemangle",
"filetime",
"flagset",
"globset",
"log",
"memmap2",
"num-traits",
"object",
"ppc750cl",
"semver",
"serde",
"serde_json",
"serde_yaml",
"similar",
]
[[package]]
name = "object"
version = "0.32.1"
version = "0.32.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
dependencies = [
"crc32fast",
"hashbrown",
@ -775,9 +823,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.69"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
dependencies = [
"unicode-ident",
]
@ -796,9 +844,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
dependencies = [
"proc-macro2",
]
@ -825,9 +873,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.3.5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
@ -935,30 +983,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.192"
name = "semver"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.192"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
name = "serde_json"
version = "1.0.108"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
dependencies = [
"itoa",
"ryu",
@ -973,14 +1027,14 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
name = "serde_yaml"
version = "0.9.27"
version = "0.9.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cc7a1570e38322cfe4154732e5110f887ea57e22b76f4bfd32b5bdd3368666c"
checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f"
dependencies = [
"indexmap",
"itoa",
@ -1009,6 +1063,12 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "similar"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21"
[[package]]
name = "smallvec"
version = "1.11.2"
@ -1054,9 +1114,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.39"
version = "2.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
dependencies = [
"proc-macro2",
"quote",
@ -1108,7 +1168,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
@ -1157,7 +1217,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]
[[package]]
@ -1312,7 +1372,16 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.5",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.4",
]
[[package]]
@ -1330,6 +1399,21 @@ dependencies = [
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [
"windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.4",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@ -1342,6 +1426,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@ -1354,6 +1444,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@ -1366,6 +1462,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@ -1378,6 +1480,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@ -1390,6 +1498,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@ -1402,6 +1516,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@ -1414,6 +1534,12 @@ version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]]
name = "winnow"
version = "0.5.19"
@ -1446,5 +1572,5 @@ checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"syn 2.0.52",
]

View File

@ -47,6 +47,7 @@ memmap2 = "0.9.0"
multimap = "0.9.1"
nintendo-lz = "0.1.3"
num_enum = "0.7.1"
objdiff-core = { git = "https://github.com/encounter/objdiff", rev = "5b9ac93c084bd0a9ae710e8c8195c4b0db939b8a", features = ["ppc"] }
object = { version = "0.32.1", features = ["read_core", "std", "elf", "write_std"], default-features = false }
once_cell = "1.18.0"
owo-colors = { version = "3.5.0", features = ["supports-colors"] }

View File

@ -836,7 +836,8 @@ fn split_write_obj(
}
debug!("Splitting {} objects", module.obj.link_order.len());
let split_objs = split_obj(&module.obj)?;
let module_name = module.config.name().to_string();
let split_objs = split_obj(&module.obj, Some(module_name.as_str()))?;
debug!("Writing object files");
DirBuilder::new()
@ -855,7 +856,7 @@ fn split_write_obj(
module.obj.symbols.by_name("_prolog")?.map(|(_, s)| s.name.clone())
};
let mut out_config = OutputModule {
name: module.config.name().to_string(),
name: module_name,
module_id,
ldscript: out_dir.join("ldscript.lcf"),
units: Vec::with_capacity(split_objs.len()),

View File

@ -8,6 +8,7 @@ use std::{
use anyhow::{anyhow, bail, ensure, Context, Result};
use argp::FromArgs;
use objdiff_core::obj::split_meta::{SplitMeta, SPLITMETA_SECTION};
use object::{
elf,
write::{Mangling, SectionId, SymbolId},
@ -148,7 +149,7 @@ fn disasm(args: DisasmArgs) -> Result<()> {
match obj.kind {
ObjKind::Executable => {
log::info!("Splitting {} objects", obj.link_order.len());
let split_objs = split_obj(&obj)?;
let split_objs = split_obj(&obj, None)?;
let asm_dir = args.out.join("asm");
let include_dir = args.out.join("include");
@ -183,7 +184,7 @@ fn split(args: SplitArgs) -> Result<()> {
let mut file_map = HashMap::<String, Vec<u8>>::new();
let split_objs = split_obj(&obj)?;
let split_objs = split_obj(&obj, None)?;
for (unit, split_obj) in obj.link_order.iter().zip(&split_objs) {
let out_obj = write_elf(split_obj, false)?;
match file_map.entry(unit.name.clone()) {
@ -596,5 +597,27 @@ fn info(args: InfoArgs) -> Result<()> {
}
}
if let Some(split_meta_section) = in_file.section_by_name(SPLITMETA_SECTION) {
let data = split_meta_section.uncompressed_data()?;
if !data.is_empty() {
let meta =
SplitMeta::from_reader(&mut data.as_ref(), in_file.endianness(), in_file.is_64())
.context("While reading .splitmeta section")?;
println!("\nSplit metadata (.splitmeta):");
if let Some(generator) = &meta.generator {
println!("\tGenerator: {}", generator);
}
if let Some(virtual_addresses) = &meta.virtual_addresses {
println!("\tVirtual addresses:");
println!("\t{: >10} | {: <10}", "Addr", "Symbol");
for (symbol, addr) in in_file.symbols().zip(virtual_addresses) {
if symbol.is_definition() {
println!("\t{: >10} | {: <10}", format!("{:#X}", addr), symbol.name()?);
}
}
}
}
}
Ok(())
}

View File

@ -485,7 +485,7 @@ fn merge(args: MergeArgs) -> Result<()> {
align: mod_section.align,
elf_index: mod_section.elf_index,
relocations: Default::default(),
original_address: mod_section.original_address,
virtual_address: mod_section.virtual_address,
file_offset: mod_section.file_offset,
section_known: mod_section.section_known,
splits: mod_section.splits.clone(),

View File

@ -100,7 +100,7 @@ enum SubCommand {
// Duplicated from supports-color so we can check early.
fn env_no_color() -> bool {
match env::var("NO_COLOR").as_deref() {
Ok("0") | Err(_) => false,
Ok("") | Ok("0") | Err(_) => false,
Ok(_) => true,
}
}

View File

@ -10,6 +10,7 @@ use std::{
};
use anyhow::{anyhow, bail, ensure, Result};
use objdiff_core::obj::split_meta::SplitMeta;
pub use relocations::{ObjReloc, ObjRelocKind, ObjRelocations};
pub use sections::{ObjSection, ObjSectionKind, ObjSections};
pub use splits::{ObjSplit, ObjSplits};
@ -55,6 +56,7 @@ pub struct ObjInfo {
pub sections: ObjSections,
pub entry: Option<u64>,
pub mw_comment: Option<MWComment>,
pub split_meta: Option<SplitMeta>,
// Linker generated
pub sda2_base: Option<u32>,
@ -94,6 +96,7 @@ impl ObjInfo {
sections: ObjSections::new(kind, sections),
entry: None,
mw_comment: Default::default(),
split_meta: None,
sda2_base: None,
sda_base: None,
stack_address: None,

View File

@ -28,7 +28,7 @@ pub struct ObjSection {
/// REL files reference the original ELF section indices
pub elf_index: usize,
pub relocations: ObjRelocations,
pub original_address: u64,
pub virtual_address: Option<u64>,
pub file_offset: u64,
pub section_known: bool,
pub splits: ObjSplits,

View File

@ -89,7 +89,7 @@ where W: Write + ?Sized {
.or_else(|| vec.iter().find(|e| e.kind == SymbolEntryKind::Start))
.map(|e| e.index);
if target_symbol_idx.is_none() {
let display_address = address as u64 + section.original_address;
let display_address = address as u64 + section.virtual_address.unwrap_or(0);
let symbol_idx = symbols.len();
symbols.push(ObjSymbol {
name: format!(".L_{display_address:08X}"),
@ -148,7 +148,7 @@ where W: Write + ?Sized {
.iter()
.any(|e| e.kind == SymbolEntryKind::Label || e.kind == SymbolEntryKind::Start)
{
let display_address = address + target_section.original_address;
let display_address = address + target_section.virtual_address.unwrap_or(0);
let symbol_idx = symbols.len();
symbols.push(ObjSymbol {
name: format!(".L_{display_address:08X}"),
@ -246,7 +246,7 @@ where
for ins in disasm_iter(data, address) {
let reloc = relocations.get(&ins.addr);
let file_offset = section.file_offset + (ins.addr as u64 - section.address);
write_ins(w, symbols, ins, reloc, file_offset, section.original_address)?;
write_ins(w, symbols, ins, reloc, file_offset, section.virtual_address)?;
}
Ok(())
}
@ -257,7 +257,7 @@ fn write_ins<W>(
mut ins: Ins,
reloc: Option<&ObjReloc>,
file_offset: u64,
section_address: u64,
section_vaddr: Option<u64>,
) -> Result<()>
where
W: Write + ?Sized,
@ -265,7 +265,7 @@ where
write!(
w,
"/* {:08X} {:08X} {:02X} {:02X} {:02X} {:02X} */\t",
ins.addr as u64 + section_address,
ins.addr as u64 + section_vaddr.unwrap_or(0),
file_offset,
(ins.code >> 24) & 0xFF,
(ins.code >> 16) & 0xFF,
@ -466,7 +466,7 @@ where
let dbg_symbols = vec.iter().map(|e| &symbols[e.index]).collect_vec();
bail!(
"Unaligned symbol entry @ {:#010X}:\n\t{:?}",
section.original_address as u32 + sym_addr,
section.virtual_address.unwrap_or(0) as u32 + sym_addr,
dbg_symbols
);
}
@ -838,11 +838,12 @@ fn write_section_header<W>(
where
W: Write + ?Sized,
{
let section_virtual_address = section.virtual_address.unwrap_or(0);
writeln!(
w,
"\n# {:#010X} - {:#010X}",
start as u64 + section.original_address,
end as u64 + section.original_address
start as u64 + section_virtual_address,
end as u64 + section_virtual_address
)?;
match section.name.as_str() {
".text" if subsection == 0 => {

View File

@ -430,7 +430,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
align: 0,
elf_index: 0,
relocations: Default::default(),
original_address: 0,
virtual_address: Some(dol_section.address as u64),
file_offset: dol_section.file_offset as u64,
section_known: known,
splits: Default::default(),
@ -460,7 +460,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
align: 0,
elf_index: 0,
relocations: Default::default(),
original_address: 0,
virtual_address: Some(addr as u64),
file_offset: 0,
section_known: false,
splits: Default::default(),
@ -480,7 +480,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
align: 0,
elf_index: 0,
relocations: Default::default(),
original_address: 0,
virtual_address: Some(bss_section.address as u64),
file_offset: 0,
section_known: false,
splits: Default::default(),
@ -507,7 +507,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
align: 0,
elf_index: 0,
relocations: Default::default(),
original_address: 0,
virtual_address: Some(bss_sections[0].0 as u64),
file_offset: 0,
section_known: false,
splits: Default::default(),
@ -521,7 +521,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result<ObjInfo> {
align: 0,
elf_index: 0,
relocations: Default::default(),
original_address: 0,
virtual_address: Some(bss_sections[1].0 as u64),
file_offset: 0,
section_known: false,
splits: Default::default(),

View File

@ -9,6 +9,7 @@ use anyhow::{anyhow, bail, ensure, Context, Result};
use cwdemangle::demangle;
use flagset::Flags;
use indexmap::IndexMap;
use objdiff_core::obj::split_meta::{SplitMeta, SHT_SPLITMETA, SPLITMETA_SECTION};
use object::{
elf,
elf::{SHF_ALLOC, SHF_EXECINSTR, SHF_WRITE, SHT_NOBITS, SHT_PROGBITS},
@ -95,7 +96,7 @@ where P: AsRef<Path> {
align: section.align(),
elf_index: section.index().0,
relocations: Default::default(),
original_address: 0, // TODO load from abs symbol
virtual_address: None, // Loaded from section symbol
file_offset: section.file_range().map(|(v, _)| v).unwrap_or_default(),
section_known: true,
splits: Default::default(),
@ -127,6 +128,26 @@ where P: AsRef<Path> {
None
};
let split_meta = if let Some(split_meta_section) = obj_file.section_by_name(SPLITMETA_SECTION) {
let data = split_meta_section.uncompressed_data()?;
if data.is_empty() {
None
} else {
let mut reader = Cursor::new(&*data);
let metadata =
SplitMeta::from_reader(&mut reader, obj_file.endianness(), obj_file.is_64())
.context("While reading .splitmeta section")?;
log::debug!("Loaded .splitmeta section");
ensure!(
data.len() - reader.position() as usize == 0,
".splitmeta section data not fully read"
);
Some(metadata)
}
} else {
None
};
let mut symbols: Vec<ObjSymbol> = vec![];
let mut symbol_indexes: Vec<Option<usize>> = vec![];
let mut section_starts = IndexMap::<String, Vec<(u64, String)>>::new();
@ -209,6 +230,16 @@ where P: AsRef<Path> {
let section_index = symbol
.section_index()
.ok_or_else(|| anyhow!("Section symbol without section"))?;
// Resolve original address from split metadata
if let Some(addr) = split_meta
.as_ref()
.and_then(|m| m.virtual_addresses.as_ref())
.and_then(|v| v.get(symbol.index().0).cloned())
{
sections[section_index.0].virtual_address = Some(addr);
}
let section = obj_file.section_by_index(section_index)?;
let section_name = section.name()?.to_string();
match &mut boundary_state {
@ -335,6 +366,7 @@ where P: AsRef<Path> {
let mut obj = ObjInfo::new(kind, architecture, obj_name, symbols, sections);
obj.entry = NonZeroU64::new(obj_file.entry()).map(|n| n.get());
obj.mw_comment = mw_comment.map(|(header, _)| header);
obj.split_meta = split_meta;
obj.sda2_base = sda2_base;
obj.sda_base = sda_base;
obj.stack_address = stack_address;
@ -348,7 +380,7 @@ where P: AsRef<Path> {
pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
let mut out_data = Vec::new();
let mut writer = object::write::elf::Writer::new(Endianness::Big, false, &mut out_data);
let mut writer = Writer::new(Endianness::Big, false, &mut out_data);
struct OutSection {
index: SectionIndex,
@ -357,6 +389,7 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
rela_offset: usize,
name: StringId,
rela_name: Option<StringId>,
virtual_address: Option<u64>,
}
struct OutSymbol {
#[allow(dead_code)]
@ -376,6 +409,7 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
rela_offset: 0,
name,
rela_name: None,
virtual_address: section.virtual_address,
});
}
@ -395,11 +429,12 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
writer.reserve_strtab_section_index();
writer.reserve_shstrtab_section_index();
// Generate comment section
// Generate .comment section
let mut comment_data = if let Some(mw_comment) = &obj.mw_comment {
let mut comment_data = Vec::<u8>::with_capacity(0x2C + obj.symbols.count() * 8);
// Reserve section
let name = writer.add_section_name(".comment".as_bytes());
let index = writer.reserve_section_index();
let out_section_idx = out_sections.len();
out_sections.push(OutSection {
index,
rela_index: None,
@ -407,12 +442,42 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
rela_offset: 0,
name,
rela_name: None,
virtual_address: None,
});
// Generate .comment data
let mut comment_data = Vec::<u8>::with_capacity(0x2C + obj.symbols.count() * 8);
mw_comment.to_writer_static(&mut comment_data, Endian::Big)?;
// Null symbol
CommentSym { align: 0, vis_flags: 0, active_flags: 0 }
.to_writer_static(&mut comment_data, Endian::Big)?;
Some(comment_data)
Some((comment_data, out_section_idx))
} else {
None
};
// Generate .splitmeta section
let mut split_meta = if let Some(metadata) = &obj.split_meta {
// Reserve section
let name = writer.add_section_name(SPLITMETA_SECTION.as_bytes());
let index = writer.reserve_section_index();
let out_section_idx = out_sections.len();
out_sections.push(OutSection {
index,
rela_index: None,
offset: 0,
rela_offset: 0,
name,
rela_name: None,
virtual_address: None,
});
// Generate .splitmeta data
let mut out = metadata.clone();
out.virtual_addresses = Some(vec![
0, // Null symbol
]);
Some((out, out_section_idx))
} else {
None
};
@ -449,10 +514,15 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
st_size: 0,
},
});
if let Some(comment_data) = &mut comment_data {
if let Some((comment_data, _)) = &mut comment_data {
CommentSym { align: 1, vis_flags: 0, active_flags: 0 }
.to_writer_static(comment_data, Endian::Big)?;
}
if let Some(virtual_addresses) =
split_meta.as_mut().and_then(|(m, _)| m.virtual_addresses.as_mut())
{
virtual_addresses.push(0);
}
section_symbol_offset += 1;
}
@ -472,10 +542,15 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
};
num_local = writer.symbol_count();
out_symbols.push(OutSymbol { index, sym });
if let Some(comment_data) = &mut comment_data {
if let Some((comment_data, _)) = &mut comment_data {
CommentSym { align: section.align as u32, vis_flags: 0, active_flags: 0 }
.to_writer_static(comment_data, Endian::Big)?;
}
if let Some(virtual_addresses) =
split_meta.as_mut().and_then(|(m, _)| m.virtual_addresses.as_mut())
{
virtual_addresses.push(section.virtual_address.unwrap_or(0));
}
}
}
@ -495,7 +570,8 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
continue;
}
let section_index = symbol.section.and_then(|idx| out_sections.get(idx)).map(|s| s.index);
let section = symbol.section.and_then(|idx| out_sections.get(idx));
let section_index = section.map(|s| s.index);
let index = writer.reserve_symbol_index(section_index);
let name_index = if symbol.name.is_empty() {
None
@ -539,9 +615,18 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
}
out_symbols.push(OutSymbol { index, sym });
symbol_map[symbol_index] = Some(index.0);
if let Some(comment_data) = &mut comment_data {
if let Some((comment_data, _)) = &mut comment_data {
CommentSym::from(symbol, export_all).to_writer_static(comment_data, Endian::Big)?;
}
if let Some(virtual_addresses) =
split_meta.as_mut().and_then(|(m, _)| m.virtual_addresses.as_mut())
{
if let Some(section_vaddr) = section.and_then(|s| s.virtual_address) {
virtual_addresses.push(section_vaddr + symbol.address);
} else {
virtual_addresses.push(0);
}
}
}
writer.reserve_file_header();
@ -576,12 +661,18 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
writer.reserve_strtab();
writer.reserve_shstrtab();
// Reserve comment section
if let Some(comment_data) = &comment_data {
let out_section = out_sections.last_mut().unwrap();
// Reserve .comment section
if let Some((comment_data, idx)) = &comment_data {
let out_section = &mut out_sections[*idx];
out_section.offset = writer.reserve(comment_data.len(), 32);
}
// Reserve .splitmeta section
if let Some((metadata, idx)) = &split_meta {
let out_section = &mut out_sections[*idx];
out_section.offset = writer.reserve(metadata.write_size(false), 32);
}
writer.reserve_section_headers();
writer.write_file_header(&object::write::elf::FileHeader {
@ -688,13 +779,24 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
writer.write_shstrtab();
// Write comment section
if let Some(comment_data) = &comment_data {
let out_section = out_sections.last().unwrap();
if let Some((comment_data, idx)) = &comment_data {
let out_section = &out_sections[*idx];
writer.write_align(32);
ensure!(writer.len() == out_section.offset);
writer.write(comment_data);
}
// Write .splitmeta section
if let Some((metadata, idx)) = &split_meta {
let out_section = &out_sections[*idx];
writer.write_align(32);
ensure!(writer.len() == out_section.offset);
// object::write::elf::Writer doesn't implement std::io::Write...
let mut data = Vec::with_capacity(metadata.write_size(false));
metadata.to_writer(&mut data, object::BigEndian, false)?;
writer.write(&data);
}
writer.write_null_section_header();
for ((_, section), out_section) in obj.sections.iter().zip(&out_sections) {
writer.write_section_header(&SectionHeader {
@ -737,9 +839,9 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
writer.write_strtab_section_header();
writer.write_shstrtab_section_header();
// Write comment section header
if let Some(comment_data) = &comment_data {
let out_section = out_sections.last().unwrap();
// Write .comment section header
if let Some((comment_data, idx)) = &comment_data {
let out_section = &out_sections[*idx];
writer.write_section_header(&SectionHeader {
name: Some(out_section.name),
sh_type: SHT_PROGBITS,
@ -754,6 +856,23 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result<Vec<u8>> {
});
}
// Write .splitmeta section header
if let Some((metadata, idx)) = &split_meta {
let out_section = &out_sections[*idx];
writer.write_section_header(&SectionHeader {
name: Some(out_section.name),
sh_type: SHT_SPLITMETA,
sh_flags: 0,
sh_addr: 0,
sh_offset: out_section.offset as u64,
sh_size: metadata.write_size(false) as u64,
sh_link: 0,
sh_info: 0,
sh_addralign: 1,
sh_entsize: 1,
});
}
ensure!(writer.reserved_len() == writer.len());
Ok(out_data)
}

View File

@ -420,7 +420,7 @@ where R: Read + Seek + ?Sized {
.unwrap_or_default() as u64,
elf_index: idx,
relocations: Default::default(),
original_address: 0,
virtual_address: None, // TODO option to set?
file_offset: offset as u64,
section_known,
splits: Default::default(),

View File

@ -410,7 +410,7 @@ where R: Read + Seek + ?Sized {
align: 0,
elf_index: idx as usize,
relocations: Default::default(),
original_address: 0,
virtual_address: None, // TODO option to set?
file_offset: offset as u64,
section_known: false,
splits: Default::default(),

View File

@ -5,6 +5,7 @@ use std::{
use anyhow::{anyhow, bail, ensure, Context, Result};
use itertools::Itertools;
use objdiff_core::obj::split_meta::SplitMeta;
use petgraph::{graph::NodeIndex, Graph};
use sanitise_file_name::sanitize_with_options;
use tracing_attributes::instrument;
@ -882,7 +883,7 @@ fn resolve_link_order(obj: &ObjInfo) -> Result<Vec<ObjUnit>> {
/// Split an object into multiple relocatable objects.
#[instrument(level = "debug", skip(obj))]
pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
pub fn split_obj(obj: &ObjInfo, module_name: Option<&str>) -> Result<Vec<ObjInfo>> {
let mut objects: Vec<ObjInfo> = vec![];
let mut object_symbols: Vec<Vec<Option<usize>>> = vec![];
let mut name_to_obj: HashMap<String, usize> = HashMap::new();
@ -903,6 +904,12 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
} else {
split_obj.mw_comment = obj.mw_comment.clone();
}
split_obj.split_meta = Some(SplitMeta {
generator: Some(format!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))),
module_name: module_name.map(str::to_string),
module_id: Some(obj.module_id),
virtual_addresses: None,
});
objects.push(split_obj);
}
@ -1083,7 +1090,7 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
align,
elf_index: out_section_idx + 1,
relocations: ObjRelocations::new(out_relocations)?,
original_address: current_address.address as u64,
virtual_address: Some(current_address.address as u64),
file_offset: section.file_offset
+ (current_address.address as u64 - section.address),
section_known: true,
@ -1148,7 +1155,7 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
else {
bail!(
"Bad extabindex relocation @ {:#010X}",
reloc_address as u64 + section.original_address
reloc_address as u64 + section.virtual_address.unwrap_or(0)
);
};
let target_section = &obj.sections.at_address(target_addr)?.1.name;
@ -1158,9 +1165,9 @@ pub fn split_obj(obj: &ObjInfo) -> Result<Vec<ObjInfo>> {
\tTarget object: {}:{:#010X} ({})\n\
\tTarget symbol: {:#010X} ({})\n\
This will cause the linker to crash.\n",
reloc_address as u64 + section.original_address,
reloc_address as u64 + section.virtual_address.unwrap_or(0),
section.name,
section.original_address,
section.virtual_address.unwrap_or(0),
out_obj.name,
target_section,
target_addr,