Skip to content

Commit

Permalink
REL section alignment fixes
Browse files Browse the repository at this point in the history
- Honor section alignment from splits.txt when writing RELs
- Better heuristic for determining REL section alignment on initial analysis
  • Loading branch information
encounter committed Sep 26, 2023
1 parent 610a2e5 commit c354c6d
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "decomp-toolkit"
description = "Yet another GameCube/Wii decompilation toolkit."
authors = ["Luke Street <[email protected]>"]
license = "MIT OR Apache-2.0"
version = "0.5.3"
version = "0.5.4"
edition = "2021"
publish = false
build = "build.rs"
Expand Down
7 changes: 5 additions & 2 deletions src/cmd/dol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use crate::{
file::{buf_reader, buf_writer, map_file, touch, verify_hash, FileIterator},
lcf::{asm_path_for_unit, generate_ldscript, obj_path_for_unit},
map::apply_map_file,
rel::{process_rel, process_rel_header},
rel::{process_rel, process_rel_header, update_rel_section_alignment},
rso::{process_rso, DOL_SECTION_ABS, DOL_SECTION_NAMES},
split::{is_linker_generated_object, split_obj, update_splits},
IntoCow, ToCow,
Expand Down Expand Up @@ -856,7 +856,7 @@ fn load_analyze_rel(config: &ProjectConfig, module_config: &ModuleConfig) -> Res
if let Some(hash_str) = &module_config.hash {
verify_hash(file.as_slice(), hash_str)?;
}
let (_, mut module_obj) =
let (header, mut module_obj) =
process_rel(&mut Cursor::new(file.as_slice()), module_config.name().as_ref())?;

if let Some(comment_version) = config.mw_comment_version {
Expand Down Expand Up @@ -895,6 +895,9 @@ fn load_analyze_rel(config: &ProjectConfig, module_config: &ModuleConfig) -> Res
// Create _ctors and _dtors symbols if missing
update_ctors_dtors(&mut module_obj)?;

// Determine REL section alignment
update_rel_section_alignment(&mut module_obj, &header)?;

Ok((module_obj, dep))
}

Expand Down
41 changes: 27 additions & 14 deletions src/cmd/rel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use crate::{
cmd::dol::{ModuleConfig, ProjectConfig},
obj::{ObjInfo, ObjReloc, ObjRelocKind, ObjSection, ObjSectionKind, ObjSymbol},
util::{
config::is_auto_symbol,
config::{is_auto_symbol, read_splits_sections, SectionDef},
dol::process_dol,
elf::{to_obj_reloc_kind, write_elf},
file::{buf_reader, buf_writer, map_file, process_rsp, verify_hash, FileIterator},
Expand Down Expand Up @@ -153,20 +153,25 @@ fn match_section_index(
// })
}

fn load_rel(module_config: &ModuleConfig) -> Result<(RelHeader, Vec<RelSectionHeader>)> {
fn load_rel(module_config: &ModuleConfig) -> Result<RelInfo> {
let file = map_file(&module_config.object)?;
if let Some(hash_str) = &module_config.hash {
verify_hash(file.as_slice(), hash_str)?;
}
let mut reader = file.as_reader();
let header = process_rel_header(&mut reader)?;
let sections = process_rel_sections(&mut reader, &header)?;
Ok((header, sections))
let section_defs = if let Some(splits_path) = &module_config.splits {
read_splits_sections(splits_path)?
} else {
None
};
Ok((header, sections, section_defs))
}

fn resolve_relocations(
module: &File,
existing_headers: &BTreeMap<u32, (RelHeader, Vec<RelSectionHeader>)>,
existing_headers: &BTreeMap<u32, RelInfo>,
module_id: usize,
symbol_map: &FxHashMap<&[u8], (usize, SymbolIndex)>,
modules: &[(File, PathBuf)],
Expand All @@ -177,11 +182,12 @@ fn resolve_relocations(
if !matches!(section.name(), Ok(name) if PERMITTED_SECTIONS.contains(&name)) {
continue;
}
let section_index = if let Some((_, sections)) = existing_headers.get(&(module_id as u32)) {
match_section_index(module, section.index(), sections)?
} else {
section.index().0
} as u8;
let section_index =
if let Some((_, sections, _)) = existing_headers.get(&(module_id as u32)) {
match_section_index(module, section.index(), sections)?
} else {
section.index().0
} as u8;
for (address, reloc) in section.relocations() {
let reloc_target = match reloc.target() {
RelocationTarget::Symbol(idx) => {
Expand All @@ -208,7 +214,7 @@ fn resolve_relocations(
(module_id, reloc_target)
};
let target_section_index = target_symbol.section_index().unwrap();
let target_section = if let Some((_, sections)) =
let target_section = if let Some((_, sections, _)) =
existing_headers.get(&(target_module_id as u32))
{
match_section_index(&modules[target_module_id].0, target_section_index, sections)?
Expand All @@ -231,19 +237,21 @@ fn resolve_relocations(
Ok(resolved)
}

type RelInfo = (RelHeader, Vec<RelSectionHeader>, Option<Vec<SectionDef>>);

fn make(args: MakeArgs) -> Result<()> {
let total = Instant::now();

// Load existing REL headers (if specified)
let mut existing_headers = BTreeMap::<u32, (RelHeader, Vec<RelSectionHeader>)>::new();
let mut existing_headers = BTreeMap::<u32, RelInfo>::new();
if let Some(config_path) = &args.config {
let config: ProjectConfig = serde_yaml::from_reader(&mut buf_reader(config_path)?)?;
for module_config in &config.modules {
let _span = info_span!("module", name = %module_config.name()).entered();
let (header, sections) = load_rel(module_config).with_context(|| {
let info = load_rel(module_config).with_context(|| {
format!("While loading REL '{}'", module_config.object.display())
})?;
existing_headers.insert(header.module_id, (header, sections));
existing_headers.insert(info.0.module_id, info);
}
}

Expand Down Expand Up @@ -316,14 +324,19 @@ fn make(args: MakeArgs) -> Result<()> {
bss_align: None,
section_count: None,
quiet: args.no_warn,
section_align: None,
};
if let Some((header, _)) = existing_headers.get(&(module_id as u32)) {
if let Some((header, _, section_defs)) = existing_headers.get(&(module_id as u32)) {
info.version = header.version;
info.name_offset = Some(header.name_offset);
info.name_size = Some(header.name_size);
info.align = header.align;
info.bss_align = header.bss_align;
info.section_count = Some(header.num_sections as usize);
info.section_align = section_defs
.as_ref()
.map(|defs| defs.iter().map(|def| def.align).collect())
.unwrap_or_default();
}
let rel_path = path.with_extension("rel");
let mut w = buf_writer(&rel_path)?;
Expand Down
47 changes: 43 additions & 4 deletions src/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,10 @@ struct SplitUnit {
comment_version: Option<u8>,
}

struct SectionDef {
name: String,
kind: Option<ObjSectionKind>,
align: Option<u32>,
pub struct SectionDef {
pub name: String,
pub kind: Option<ObjSectionKind>,
pub align: Option<u32>,
}

enum SplitLine {
Expand Down Expand Up @@ -626,3 +626,42 @@ pub fn apply_splits<R: BufRead>(r: R, obj: &mut ObjInfo) -> Result<()> {
}
Ok(())
}

pub fn read_splits_sections<P: AsRef<Path>>(path: P) -> Result<Option<Vec<SectionDef>>> {
if !path.as_ref().is_file() {
return Ok(None);
}
let file = map_file(path)?;
let r = file.as_reader();
let mut sections = Vec::new();
let mut state = SplitState::None;
for result in r.lines() {
let line = match result {
Ok(line) => line,
Err(e) => return Err(e.into()),
};
let split_line = parse_split_line(&line, &state)?;
match (&mut state, split_line) {
(SplitState::None | SplitState::Unit(_), SplitLine::SectionsStart) => {
state = SplitState::Sections(0);
}
(SplitState::Sections(index), SplitLine::Section(def)) => {
sections.push(def);
*index += 1;
}
(SplitState::Sections(_), SplitLine::None) => {
// Continue
}
(SplitState::Sections(_), _) => {
// End of sections
break;
}
_ => {}
}
}
if sections.is_empty() {
Ok(None)
} else {
Ok(Some(sections))
}
}
8 changes: 4 additions & 4 deletions src/util/lcf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use anyhow::{bail, Result};
use itertools::Itertools;
use path_slash::PathBufExt;

use crate::obj::{ObjInfo, ObjKind};

#[inline]
const fn align_up(value: u32, align: u32) -> u32 { (value + (align - 1)) & !(align - 1) }
use crate::{
obj::{ObjInfo, ObjKind},
util::align_up,
};

const LCF_TEMPLATE: &str = include_str!("../../assets/ldscript.lcf");
const LCF_PARTIAL_TEMPLATE: &str = include_str!("../../assets/ldscript_partial.lcf");
Expand Down
3 changes: 3 additions & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ pub mod signatures;
pub mod split;
pub mod yaz0;

#[inline]
pub const fn align_up(value: u32, align: u32) -> u32 { (value + (align - 1)) & !(align - 1) }

/// Creates a fixed-size array reference from a slice.
#[macro_export]
macro_rules! array_ref {
Expand Down
Loading

0 comments on commit c354c6d

Please sign in to comment.