Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
/build.ps1
/TODO.md
/cli/target
/temp/
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ resolver = "2"

[profile.release]
lto = true

[profile.release-fast]
inherits = "release"
lto = false
12 changes: 12 additions & 0 deletions assets/arm9.lcf.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ MEMORY \{
{{ for module in modules -}}
{module.name} : ORIGIN = {module.origin} > {module.output_file}
{{ endfor }}
SPACE : ORIGIN = AFTER(
{{- for module in modules -}}
{{- if not module.in_tcm -}}
{{- if not @first -}}, {{ endif -}}
{module.name}
{{- endif -}}
{{- endfor -}}
)
}

KEEP_SECTION \{
Expand All @@ -14,6 +22,10 @@ SECTIONS \{
{overlay.id_symbol} = {overlay.id};
{{ endfor }}

{{ for variable in variables -}}
{variable.symbol} = {variable.value};
{{ endfor }}

{{ for module in modules -}}
{module.link_section} : \{
ALIGNALL(4);
Expand Down
4 changes: 4 additions & 0 deletions cli/src/analysis/overlay_groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,8 @@ impl OverlayGroups {
pub fn iter(&self) -> impl Iterator<Item = &OverlayGroup> {
self.groups.iter()
}

pub fn last(&self) -> Option<&OverlayGroup> {
self.groups.last()
}
}
281 changes: 154 additions & 127 deletions cli/src/cmd/delink.rs

Large diffs are not rendered by default.

35 changes: 14 additions & 21 deletions cli/src/cmd/dis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use std::{
use anyhow::{Context, Result};
use clap::Args;
use ds_decomp::config::{
config::{Config, ConfigModule},
config::Config,
delinks::{DelinkFile, Delinks},
module::{Module, ModuleKind},
module::Module,
section::Section,
symbol::{InstructionMode, Symbol, SymbolKind, SymbolMaps},
};
Expand All @@ -18,7 +18,7 @@ use ds_rom::rom::{Rom, RomLoadOptions};
use crate::{
analysis::functions::FunctionExt,
config::{
delinks::DelinksExt,
delinks::{DelinksMap, DelinksMapOptions},
symbol::{SymDataExt, SymbolLookup},
},
util::io::create_file,
Expand All @@ -45,6 +45,13 @@ impl Disassemble {
let config = Config::from_file(&self.config_path)?;
let config_path = self.config_path.parent().unwrap();

let delinks_map = DelinksMap::from_config(&config, config_path, DelinksMapOptions {
// Set to false because we want to disassemble migrated sections like .dtcm in the same
// file. Setting this to true actually creates two files, but one gets overwritten and
// deleted by the other.
migrate_sections: false,
})?;

let rom_config_path = config_path.join(&config.rom_config);
let rom = Rom::load(&rom_config_path, RomLoadOptions {
key: None,
Expand All @@ -57,31 +64,17 @@ impl Disassemble {
})?;

let mut symbol_maps = SymbolMaps::from_config(config_path, &config)?;

self.disassemble_module(&config, &config.main_module, ModuleKind::Arm9, &mut symbol_maps, &rom)?;
for autoload in &config.autoloads {
self.disassemble_module(&config, &autoload.module, ModuleKind::Autoload(autoload.kind), &mut symbol_maps, &rom)?;
}
for overlay in &config.overlays {
self.disassemble_module(&config, &overlay.module, ModuleKind::Overlay(overlay.id), &mut symbol_maps, &rom)?;
for delinks in delinks_map.iter() {
self.disassemble_module(&config, delinks, &mut symbol_maps, &rom)?;
}

Ok(())
}

fn disassemble_module(
&self,
config: &Config,
module_config: &ConfigModule,
kind: ModuleKind,
symbol_maps: &mut SymbolMaps,
rom: &Rom,
) -> Result<()> {
fn disassemble_module(&self, config: &Config, delinks: &Delinks, symbol_maps: &mut SymbolMaps, rom: &Rom) -> Result<()> {
let config_path = self.config_path.parent().unwrap();

let delinks = Delinks::from_file_and_generate_gaps(config_path.join(&module_config.delinks), kind)?;

let module = config.load_module(config_path, symbol_maps, kind, rom)?;
let module = config.load_module(config_path, symbol_maps, delinks.module_kind(), rom)?;

for file in &delinks.files {
let (file_path, _) = file.split_file_ext();
Expand Down
66 changes: 16 additions & 50 deletions cli/src/cmd/json/delinks.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use std::path::{Path, PathBuf};
use std::path::PathBuf;

use anyhow::Result;
use clap::Args;
use ds_decomp::config::{
config::Config,
delinks::{DelinkFile, Delinks},
module::ModuleKind,
};
use ds_rom::rom::raw::AutoloadKind;
use ds_decomp::config::config::Config;
use serde::Serialize;

use crate::{cmd::ARM9_LCF_FILE_NAME, config::delinks::DelinksExt, util::path::PathExt};
use crate::{
cmd::ARM9_LCF_FILE_NAME,
config::delinks::{DelinksMap, DelinksMapOptions},
util::path::PathExt,
};

#[derive(Args)]
pub struct JsonDelinks {
Expand Down Expand Up @@ -49,15 +48,21 @@ impl JsonDelinks {
let build_path = config_dir.join(&config.build_path);
let delinks_path = config_dir.join(&config.delinks_path);

let files = Self::get_delink_files(config_dir, &config)?
.into_iter()
let delinks_map = DelinksMap::from_config(&config, config_dir, DelinksMapOptions {
// Migrating would create delink files with identical names, which is wasteful when we
// call `DelinksMap::delink_files()` later
migrate_sections: false,
})?;

let files = delinks_map
.delink_files()
.map(|file| {
let (file_path, _) = file.split_file_ext();
let base_path = if file.complete { &build_path } else { &delinks_path };
let object_to_link = base_path.join(file_path).clean().with_extension("o");
let delink_file = delinks_path.join(file_path).clean().with_extension("o");

Ok(DelinkFileJson { name: file.name, delink_file, object_to_link })
Ok(DelinkFileJson { name: file.name.clone(), delink_file, object_to_link })
})
.collect::<Result<Vec<_>>>()?;

Expand All @@ -66,43 +71,4 @@ impl JsonDelinks {

Ok(ModulesJson { arm9_lcf_file, arm9_objects_file, files })
}

pub fn get_delink_files(config_dir: &Path, config: &Config) -> Result<Vec<DelinkFile>> {
let mut delink_files = vec![];

// Main module
delink_files.extend(
Delinks::from_file_and_generate_gaps(config_dir.join(&config.main_module.delinks), ModuleKind::Arm9)?
.without_dtcm_sections()
.files,
);

// Autoloads
for autoload in &config.autoloads {
let delinks = if autoload.kind == AutoloadKind::Dtcm {
Delinks::new_dtcm(config_dir, config, &autoload.module)?
} else {
Delinks::from_file_and_generate_gaps(
config_dir.join(&autoload.module.delinks),
ModuleKind::Autoload(autoload.kind),
)?
.without_dtcm_sections()
};
delink_files.extend(delinks.files);
}

// Overlays
for overlay in &config.overlays {
delink_files.extend(
Delinks::from_file_and_generate_gaps(
config_dir.join(&overlay.module.delinks),
ModuleKind::Overlay(overlay.id),
)?
.without_dtcm_sections()
.files,
);
}

Ok(delink_files)
}
}
Loading