Skip to content

Commit 0cfc5df

Browse files
committed
Overhauled common BSS support & more
- With a map, attempts to detect and handle common BSS automatically - With a map, attempts to detect and correct inflated common BSS bug (< GC 2.7 linker) - Support for "stripped" symbols, sometimes required to match inflated common BSS sizes - Warns on duplicated TUs in a map (other than common BSS) - Automatically adds `comment:0` to `.s` TUs from a map (avoids linker crash)
1 parent 5c22c88 commit 0cfc5df

File tree

10 files changed

+269
-95
lines changed

10 files changed

+269
-95
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "decomp-toolkit"
33
description = "Yet another GameCube/Wii decompilation toolkit."
44
authors = ["Luke Street <[email protected]>"]
55
license = "MIT OR Apache-2.0"
6-
version = "0.6.3"
6+
version = "0.6.4"
77
edition = "2021"
88
publish = false
99
repository = "https://github.com/encounter/decomp-toolkit"

src/cmd/dol.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,7 @@ fn load_analyze_dol(config: &ProjectConfig) -> Result<AnalyzeResult> {
739739
}
740740

741741
if let Some(map_path) = &config.base.map {
742-
apply_map_file(map_path, &mut obj)?;
742+
apply_map_file(map_path, &mut obj, config.common_start, config.mw_comment_version)?;
743743
dep.push(map_path.clone());
744744
}
745745

@@ -963,7 +963,7 @@ fn load_analyze_rel(config: &ProjectConfig, module_config: &ModuleConfig) -> Res
963963

964964
let mut dep = vec![module_config.object.clone()];
965965
if let Some(map_path) = &module_config.map {
966-
apply_map_file(map_path, &mut module_obj)?;
966+
apply_map_file(map_path, &mut module_obj, None, None)?;
967967
dep.push(map_path.clone());
968968
}
969969

@@ -1451,11 +1451,10 @@ fn diff(args: DiffArgs) -> Result<()> {
14511451
log::info!("Loading {}", args.elf_file.display());
14521452
let linked_obj = process_elf(&args.elf_file)?;
14531453

1454-
for orig_sym in obj
1455-
.symbols
1456-
.iter()
1457-
.filter(|s| !matches!(s.kind, ObjSymbolKind::Unknown | ObjSymbolKind::Section))
1458-
{
1454+
let common_bss = obj.sections.common_bss_start();
1455+
for orig_sym in obj.symbols.iter().filter(|s| {
1456+
!matches!(s.kind, ObjSymbolKind::Unknown | ObjSymbolKind::Section) && !s.flags.is_stripped()
1457+
}) {
14591458
let Some(orig_section_index) = orig_sym.section else { continue };
14601459
let orig_section = &obj.sections[orig_section_index];
14611460
let (linked_section_index, linked_section) =
@@ -1474,7 +1473,12 @@ fn diff(args: DiffArgs) -> Result<()> {
14741473
let mut found = false;
14751474
if let Some((_, linked_sym)) = linked_sym {
14761475
if linked_sym.name.starts_with(&orig_sym.name) {
1477-
if linked_sym.size != orig_sym.size {
1476+
if linked_sym.size != orig_sym.size &&
1477+
// TODO validate common symbol sizes
1478+
// (need to account for inflation bug)
1479+
matches!(common_bss, Some((idx, addr)) if
1480+
orig_section_index == idx && orig_sym.address as u32 >= addr)
1481+
{
14781482
log::error!(
14791483
"Expected {} (type {:?}) to have size {:#X}, but found {:#X}",
14801484
orig_sym.name,

src/cmd/map.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub fn run(args: Args) -> Result<()> {
5757

5858
fn entries(args: EntriesArgs) -> Result<()> {
5959
let file = map_file(&args.map_file)?;
60-
let entries = process_map(&mut file.as_reader())?;
60+
let entries = process_map(&mut file.as_reader(), None, None)?;
6161
match entries.unit_entries.get_vec(&args.unit) {
6262
Some(vec) => {
6363
println!("Entries for {}:", args.unit);
@@ -89,7 +89,7 @@ fn entries(args: EntriesArgs) -> Result<()> {
8989
fn symbol(args: SymbolArgs) -> Result<()> {
9090
let file = map_file(&args.map_file)?;
9191
log::info!("Processing map...");
92-
let entries = process_map(&mut file.as_reader())?;
92+
let entries = process_map(&mut file.as_reader(), None, None)?;
9393
log::info!("Done!");
9494
let mut opt_ref: Option<(String, SymbolEntry)> = None;
9595

src/obj/sections.rs

+7
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ impl ObjSections {
125125
self.iter()
126126
.flat_map(|(idx, s)| s.splits.iter().map(move |(addr, split)| (idx, s, addr, split)))
127127
}
128+
129+
pub fn common_bss_start(&self) -> Option<(usize, u32)> {
130+
let Ok(Some((section_index, section))) = self.by_name(".bss") else {
131+
return None;
132+
};
133+
section.splits.iter().find(|(_, split)| split.common).map(|(addr, _)| (section_index, addr))
134+
}
128135
}
129136

130137
impl Index<usize> for ObjSections {

src/obj/symbols.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ pub enum ObjSymbolScope {
2626
}
2727

2828
flags! {
29-
#[repr(u8)]
29+
#[repr(u32)]
3030
#[derive(Deserialize_repr, Serialize_repr)]
31-
pub enum ObjSymbolFlags: u8 {
31+
pub enum ObjSymbolFlags: u32 {
3232
Global,
3333
Local,
3434
Weak,
@@ -39,6 +39,9 @@ flags! {
3939
RelocationIgnore,
4040
/// Symbol won't be written to symbols file
4141
NoWrite,
42+
/// Symbol was stripped from the original object,
43+
/// but is still useful for common BSS matching.
44+
Stripped,
4245
}
4346
}
4447

@@ -83,6 +86,9 @@ impl ObjSymbolFlagSet {
8386
#[inline]
8487
pub fn is_no_write(&self) -> bool { self.0.contains(ObjSymbolFlags::NoWrite) }
8588

89+
#[inline]
90+
pub fn is_stripped(&self) -> bool { self.0.contains(ObjSymbolFlags::Stripped) }
91+
8692
#[inline]
8793
pub fn set_scope(&mut self, scope: ObjSymbolScope) {
8894
match scope {
@@ -119,7 +125,8 @@ impl ObjSymbolFlagSet {
119125
self.0
120126
& (ObjSymbolFlags::ForceActive
121127
| ObjSymbolFlags::NoWrite
122-
| ObjSymbolFlags::RelocationIgnore)
128+
| ObjSymbolFlags::RelocationIgnore
129+
| ObjSymbolFlags::Stripped)
123130
}
124131
}
125132

@@ -212,7 +219,10 @@ impl ObjSymbols {
212219
}
213220

214221
pub fn add(&mut self, in_symbol: ObjSymbol, replace: bool) -> Result<SymbolIndex> {
215-
let opt = if let Some(section_index) = in_symbol.section {
222+
let opt = if in_symbol.flags.is_stripped() {
223+
// Stripped symbols don't overwrite existing symbols
224+
None
225+
} else if let Some(section_index) = in_symbol.section {
216226
self.at_section_address(section_index, in_symbol.address as u32).find(|(_, symbol)| {
217227
symbol.kind == in_symbol.kind ||
218228
// Replace auto symbols with real symbols
@@ -228,7 +238,8 @@ impl ObjSymbols {
228238
let replace = replace || (is_auto_symbol(existing) && !is_auto_symbol(&in_symbol));
229239
let size =
230240
if existing.size_known && in_symbol.size_known && existing.size != in_symbol.size {
231-
log::warn!(
241+
// TODO fix this and restore to warning
242+
log::debug!(
232243
"Conflicting size for {}: was {:#X}, now {:#X}",
233244
existing.name,
234245
existing.size,
@@ -336,6 +347,8 @@ impl ObjSymbols {
336347
.into_iter()
337348
.flatten()
338349
.map(move |&idx| (idx, &self.symbols[idx]))
350+
// "Stripped" symbols don't actually exist at the address
351+
.filter(|(_, sym)| !sym.flags.is_stripped())
339352
}
340353

341354
pub fn kind_at_section_address(
@@ -513,7 +526,7 @@ impl Index<SymbolIndex> for ObjSymbols {
513526
impl ObjSymbol {
514527
/// Whether this symbol can be referenced by the given relocation kind.
515528
pub fn referenced_by(&self, reloc_kind: ObjRelocKind) -> bool {
516-
if self.flags.is_relocation_ignore() {
529+
if self.flags.is_relocation_ignore() || self.flags.is_stripped() {
517530
return false;
518531
}
519532

src/util/comment.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,10 @@ impl CommentSym {
281281
vis_flags |= 0xD;
282282
}
283283
let mut active_flags = 0;
284-
if symbol.flags.is_force_active()
285-
|| (force_active
286-
&& matches!(symbol.kind, ObjSymbolKind::Function | ObjSymbolKind::Object))
284+
if !symbol.flags.is_stripped()
285+
&& (symbol.flags.is_force_active()
286+
|| (force_active
287+
&& matches!(symbol.kind, ObjSymbolKind::Function | ObjSymbolKind::Object)))
287288
{
288289
active_flags |= 0x8;
289290
}

src/util/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ pub fn parse_symbol_line(line: &str, obj: &mut ObjInfo) -> Result<Option<ObjSymb
130130
"force_active" => {
131131
symbol.flags.0 |= ObjSymbolFlags::ForceActive;
132132
}
133+
"stripped" => {
134+
symbol.flags.0 |= ObjSymbolFlags::Stripped;
135+
}
133136
"noreloc" => {
134137
ensure!(
135138
symbol.size != 0,
@@ -270,6 +273,9 @@ where W: Write + ?Sized {
270273
// if symbol.flags.is_force_active() {
271274
// write!(w, " force_active")?;
272275
// }
276+
if symbol.flags.is_stripped() {
277+
write!(w, " stripped")?;
278+
}
273279
if let Some(section) = symbol.section {
274280
if obj.blocked_ranges.contains_key(&SectionAddress::new(section, symbol.address as u32)) {
275281
write!(w, " noreloc")?;

0 commit comments

Comments
 (0)