From 3fb745fc6ca1857c871d46ddb698c28a6a05a1f2 Mon Sep 17 00:00:00 2001 From: Henry Date: Fri, 15 Aug 2025 16:23:54 -0400 Subject: [PATCH 1/2] support virtual addresses for rels --- src/cmd/dol.rs | 2 ++ src/cmd/rel.rs | 2 ++ src/obj/sections.rs | 1 + src/obj/symbols.rs | 3 +++ src/util/alf.rs | 1 + src/util/config.rs | 46 +++++++++++++++++++++++++++++++++++++++++---- src/util/dol.rs | 6 ++++++ src/util/elf.rs | 6 +++++- src/util/map.rs | 1 + src/util/rel.rs | 1 + src/util/rso.rs | 1 + src/util/split.rs | 2 ++ 12 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/cmd/dol.rs b/src/cmd/dol.rs index 5966404..6ffcf4a 100644 --- a/src/cmd/dol.rs +++ b/src/cmd/dol.rs @@ -485,6 +485,7 @@ fn apply_selfile(obj: &mut ObjInfo, buf: &[u8]) -> Result<()> { name: symbol.name.clone(), demangled_name: symbol.demangled_name.clone(), address: address as u64, + virtual_address: None, section, size: existing_symbol.size, size_known: existing_symbol.size_known, @@ -2017,6 +2018,7 @@ fn apply(args: ApplyArgs) -> Result<()> { name: linked_sym.name.clone(), demangled_name: linked_sym.demangled_name.clone(), address: linked_sym.address, + virtual_address: None, section: Some(orig_section_index), size: linked_sym.size, size_known: linked_sym.size_known, diff --git a/src/cmd/rel.rs b/src/cmd/rel.rs index 8e1cb09..1c94187 100644 --- a/src/cmd/rel.rs +++ b/src/cmd/rel.rs @@ -519,6 +519,7 @@ fn merge(args: MergeArgs) -> Result<()> { elf_index: mod_section.elf_index, relocations: Default::default(), virtual_address: mod_section.virtual_address, + virtual_address_passed_in: false, file_offset: mod_section.file_offset, section_known: mod_section.section_known, splits: mod_section.splits.clone(), @@ -529,6 +530,7 @@ fn merge(args: MergeArgs) -> Result<()> { name: mod_symbol.name.clone(), demangled_name: mod_symbol.demangled_name.clone(), address: mod_symbol.address + offset as u64, + virtual_address: None, section: Some(section_idx), size: mod_symbol.size, size_known: mod_symbol.size_known, diff --git a/src/obj/sections.rs b/src/obj/sections.rs index 6d366b5..09777cb 100644 --- a/src/obj/sections.rs +++ b/src/obj/sections.rs @@ -32,6 +32,7 @@ pub struct ObjSection { pub elf_index: SectionIndex, pub relocations: ObjRelocations, pub virtual_address: Option, + pub virtual_address_passed_in: bool, pub file_offset: u64, pub section_known: bool, pub splits: ObjSplits, diff --git a/src/obj/symbols.rs b/src/obj/symbols.rs index 0bd0b89..27df92e 100644 --- a/src/obj/symbols.rs +++ b/src/obj/symbols.rs @@ -189,6 +189,7 @@ pub struct ObjSymbol { pub name: String, pub demangled_name: Option, pub address: u64, + pub virtual_address: Option, pub section: Option, pub size: u64, pub size_known: bool, @@ -297,6 +298,7 @@ impl ObjSymbols { name: in_symbol.name, demangled_name: in_symbol.demangled_name, address: in_symbol.address, + virtual_address: in_symbol.virtual_address, section: in_symbol.section, size, size_known: existing.size_known || in_symbol.size != 0, @@ -321,6 +323,7 @@ impl ObjSymbols { name: in_symbol.name, demangled_name: in_symbol.demangled_name, address: in_symbol.address, + virtual_address: in_symbol.virtual_address, section: in_symbol.section, size: in_symbol.size, size_known: in_symbol.size != 0, diff --git a/src/util/alf.rs b/src/util/alf.rs index 35ad2bd..9ad848a 100644 --- a/src/util/alf.rs +++ b/src/util/alf.rs @@ -230,6 +230,7 @@ impl AlfSymbol { name, demangled_name, address: self.address as u64, + virtual_address: None, section: Some(self.section as SectionIndex - 1), size: self.size as u64, size_known: true, diff --git a/src/util/config.rs b/src/util/config.rs index 32a3df6..43c4d9e 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -93,9 +93,19 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result 0 { write!(w, " size:{:#X}", symbol.size)?; @@ -434,6 +444,9 @@ where W: Write + ?Sized { if section.align > 0 { write!(w, " align:{}", section.align)?; } + if section.virtual_address_passed_in { + write!(w, " virtual_address:{:#X}", section.virtual_address.unwrap())?; + } writeln!(w)?; } for unit in obj.link_order.iter().filter(|unit| all || !unit.autogenerated) { @@ -455,6 +468,13 @@ where W: Write + ?Sized { } else { split_iter.peek().map(|&(_, _, addr, _)| addr).unwrap_or(0) }; + + let (addr, end) = if section.virtual_address_passed_in { + (addr + section.virtual_address.unwrap() as u32, end + section.virtual_address.unwrap() as u32) + } else { + (addr, end) + }; + write!(w, "\t{:<11} start:{:#010X} end:{:#010X}", section.name, addr, end)?; if let Some(align) = split.align { if align != default_section_align(section) as u32 { @@ -499,6 +519,7 @@ pub struct SectionDef { pub name: String, pub kind: Option, pub align: Option, + pub virtual_address: Option, } enum SplitLine { @@ -553,7 +574,8 @@ fn parse_unit_line(captures: Captures) -> Result { fn parse_section_line(captures: Captures, state: &SplitState) -> Result { if matches!(state, SplitState::Sections(_)) { let name = &captures["name"]; - let mut section = SectionDef { name: name.to_string(), kind: None, align: None }; + let mut section = SectionDef { name: name.to_string(), kind: None, align: None, virtual_address: None, }; + for attr in captures["attrs"].split(' ').filter(|&s| !s.is_empty()) { if let Some((attr, value)) = attr.split_once(':') { @@ -567,6 +589,9 @@ fn parse_section_line(captures: Captures, state: &SplitState) -> Result { section.align = Some(parse_u32(value)?); } + "virtual_address" => { + section.virtual_address = Some(parse_u32(value)?); + } _ => bail!("Unknown section attribute '{attr}'"), } } else { @@ -665,7 +690,7 @@ where R: BufRead + ?Sized { (SplitState::None | SplitState::Unit(_), SplitLine::SectionsStart) => { state = SplitState::Sections(0); } - (SplitState::Sections(index), SplitLine::Section(SectionDef { name, kind, align })) => { + (SplitState::Sections(index), SplitLine::Section(SectionDef { name, kind, align, virtual_address })) => { let Some(obj_section) = obj.sections.get_mut(*index) else { bail!( "Section out of bounds: {} (index {}), object has {} sections", @@ -684,6 +709,10 @@ where R: BufRead + ?Sized { if let Some(align) = align { obj_section.align = align as u64; } + if let Some(virtual_address) = virtual_address { + obj_section.virtual_address = Some(virtual_address as u64); + obj_section.virtual_address_passed_in = true; + } *index += 1; } ( @@ -710,6 +739,15 @@ where R: BufRead + ?Sized { } }?; let section = obj.sections.get_mut(section_index).unwrap(); + + let (start, end) = if section.virtual_address_passed_in { + ( + start.saturating_sub(section.virtual_address.unwrap_or(0).try_into().unwrap()), + end.saturating_sub(section.virtual_address.unwrap_or(0).try_into().unwrap()) + ) + } else { + (start, end) + }; let section_end = (section.address + section.size) as u32; ensure!( section.contains_range(start..end) diff --git a/src/util/dol.rs b/src/util/dol.rs index 7278999..80f61aa 100644 --- a/src/util/dol.rs +++ b/src/util/dol.rs @@ -364,6 +364,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(addr as u64), + virtual_address_passed_in: false, file_offset: file_offset as u64, section_known: known, splits: Default::default(), @@ -417,6 +418,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(dol_section.address as u64), + virtual_address_passed_in: false, file_offset: dol_section.file_offset as u64, section_known: known, splits: Default::default(), @@ -449,6 +451,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(addr as u64), + virtual_address_passed_in: false, file_offset: 0, section_known: false, splits: Default::default(), @@ -469,6 +472,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(bss_section.address as u64), + virtual_address_passed_in: false, file_offset: 0, section_known: false, splits: Default::default(), @@ -496,6 +500,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(bss_sections[0].0 as u64), + virtual_address_passed_in: false, file_offset: 0, section_known: false, splits: Default::default(), @@ -510,6 +515,7 @@ pub fn process_dol(buf: &[u8], name: &str) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: Some(bss_sections[1].0 as u64), + virtual_address_passed_in: false, file_offset: 0, section_known: false, splits: Default::default(), diff --git a/src/util/elf.rs b/src/util/elf.rs index 7872b75..10187f2 100644 --- a/src/util/elf.rs +++ b/src/util/elf.rs @@ -100,6 +100,7 @@ pub fn process_elf(path: &Utf8NativePath) -> Result { elf_index: section.index().0 as ObjSectionIndex, relocations: Default::default(), virtual_address: None, // Loaded from section symbol + virtual_address_passed_in: false, file_offset: section.file_range().map(|(v, _)| v).unwrap_or_default(), section_known: true, splits: Default::default(), @@ -628,7 +629,10 @@ pub fn write_elf(obj: &ObjInfo, export_all: bool) -> Result> { 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) { + if symbol.virtual_address.is_some() { + virtual_addresses.push((symbol.virtual_address.unwrap()).into()); + } + else if let Some(section_vaddr) = section.and_then(|s| s.virtual_address) { virtual_addresses.push(section_vaddr + symbol.address); } else { virtual_addresses.push(0); diff --git a/src/util/map.rs b/src/util/map.rs index 6a889fe..be18b9a 100644 --- a/src/util/map.rs +++ b/src/util/map.rs @@ -917,6 +917,7 @@ pub fn create_obj(result: &MapInfo) -> Result { elf_index: 0, relocations: Default::default(), virtual_address: None, + virtual_address_passed_in: false, file_offset, section_known: true, splits: Default::default(), diff --git a/src/util/rel.rs b/src/util/rel.rs index 7d83dc7..72d4530 100644 --- a/src/util/rel.rs +++ b/src/util/rel.rs @@ -421,6 +421,7 @@ where R: Read + Seek + ?Sized { elf_index: idx as SectionIndex, relocations: Default::default(), virtual_address: None, // TODO option to set? + virtual_address_passed_in: false, file_offset: offset as u64, section_known, splits: Default::default(), diff --git a/src/util/rso.rs b/src/util/rso.rs index 94fc338..85961c1 100644 --- a/src/util/rso.rs +++ b/src/util/rso.rs @@ -455,6 +455,7 @@ where R: Read + Seek + ?Sized { elf_index: idx as SectionIndex, relocations: Default::default(), virtual_address: None, // TODO option to set? + virtual_address_passed_in: false, file_offset: offset as u64, section_known: false, splits: Default::default(), diff --git a/src/util/split.rs b/src/util/split.rs index e3ea084..a5bc96d 100644 --- a/src/util/split.rs +++ b/src/util/split.rs @@ -1163,6 +1163,7 @@ pub fn split_obj(obj: &ObjInfo, module_name: Option<&str>) -> Result) -> Result Date: Sat, 16 Aug 2025 09:52:12 -0400 Subject: [PATCH 2/2] Minor clean up and documentation improvements --- src/obj/sections.rs | 3 ++- src/obj/symbols.rs | 2 +- src/util/config.rs | 15 +++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/obj/sections.rs b/src/obj/sections.rs index 09777cb..0a759cf 100644 --- a/src/obj/sections.rs +++ b/src/obj/sections.rs @@ -32,7 +32,8 @@ pub struct ObjSection { pub elf_index: SectionIndex, pub relocations: ObjRelocations, pub virtual_address: Option, - pub virtual_address_passed_in: bool, + // This exists for virtual address support in symbols/splits.txt. + pub virtual_address_passed_in: bool, pub file_offset: u64, pub section_known: bool, pub splits: ObjSplits, diff --git a/src/obj/symbols.rs b/src/obj/symbols.rs index 27df92e..16d8135 100644 --- a/src/obj/symbols.rs +++ b/src/obj/symbols.rs @@ -189,7 +189,7 @@ pub struct ObjSymbol { pub name: String, pub demangled_name: Option, pub address: u64, - pub virtual_address: Option, + pub virtual_address: Option, // Added for REL virtual address support pub section: Option, pub size: u64, pub size_known: bool, diff --git a/src/util/config.rs b/src/util/config.rs index 43c4d9e..b9f2666 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -94,11 +94,11 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result Result