From 6aca2b2558495b586c418aab5d1bfe7908f5af0a Mon Sep 17 00:00:00 2001 From: angie Date: Wed, 24 Apr 2024 16:33:18 -0400 Subject: [PATCH] Start working on Partial linking support #20 --- slinky-cli/src/main.rs | 8 ++++- slinky/src/lib.rs | 2 ++ slinky/src/linker_writer.rs | 13 ++++--- slinky/src/partial_linker_writer.rs | 41 +++++++++++++++++++++ slinky/src/settings.rs | 56 ++++++++++++++++++++++------- 5 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 slinky/src/partial_linker_writer.rs diff --git a/slinky-cli/src/main.rs b/slinky-cli/src/main.rs index 73a8fb0..45efda2 100644 --- a/slinky-cli/src/main.rs +++ b/slinky-cli/src/main.rs @@ -16,6 +16,11 @@ struct Cli { /// Output file. Print to stdout if missing #[arg(short, long)] output: Option, + + /// Generate linker script for partial linking multiple segments. + /// Requires both `partial_scripts_path` and `partial_build_segments_path` YAML settings to be set. + #[arg(short, long, default_value_t = false)] + partial_linking: bool, } fn main() { @@ -33,7 +38,8 @@ fn main() { } writer.end_sections(); - if let Some(output_path) = cli.output { + if cli.partial_linking { + } else if let Some(output_path) = cli.output { writer .save_linker_script(&output_path) .expect("Error writing the linker script"); diff --git a/slinky/src/lib.rs b/slinky/src/lib.rs index 30f07cf..b947c18 100644 --- a/slinky/src/lib.rs +++ b/slinky/src/lib.rs @@ -15,6 +15,7 @@ mod segment; mod document; mod linker_writer; +mod partial_linker_writer; pub use error::SlinkyError; @@ -28,3 +29,4 @@ pub use segment::Segment; pub use document::Document; pub use linker_writer::LinkerWriter; +pub use partial_linker_writer::PartialLinkerWriter; diff --git a/slinky/src/linker_writer.rs b/slinky/src/linker_writer.rs index 46915cf..b9112a7 100644 --- a/slinky/src/linker_writer.rs +++ b/slinky/src/linker_writer.rs @@ -417,11 +417,6 @@ impl<'a> LinkerWriter<'a> { ret } - - #[must_use] - pub fn get(&self) -> &HashSet { - &self.linker_symbols - } } impl LinkerWriter<'_> { @@ -440,6 +435,14 @@ impl LinkerWriter<'_> { } } +// Getters / Setters +impl LinkerWriter<'_> { + #[must_use] + pub fn get_linker_symbols(&self) -> &HashSet { + &self.linker_symbols + } +} + // internal functions impl LinkerWriter<'_> { fn writeln(&mut self, line: &str) { diff --git a/slinky/src/partial_linker_writer.rs b/slinky/src/partial_linker_writer.rs new file mode 100644 index 0000000..907e497 --- /dev/null +++ b/slinky/src/partial_linker_writer.rs @@ -0,0 +1,41 @@ +/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-License-Identifier: MIT */ + +use crate::{LinkerWriter, Segment, Settings}; + +pub struct PartialLinkerWriter<'a> { + main_writer: LinkerWriter<'a>, + partial_writers: Vec>, + + settings: &'a Settings, +} + +impl<'a> PartialLinkerWriter<'a> { + pub fn new(settings: &'a Settings) -> Self { + Self { + main_writer: LinkerWriter::new(settings), + partial_writers: Vec::new(), + + settings, + } + } + + pub fn add_segment(&mut self, _segment: &Segment) { + let partial_writer = LinkerWriter::new(self.settings); + + self.partial_writers.push(partial_writer); + } +} + +// Getters / Setters +impl PartialLinkerWriter<'_> { + #[must_use] + pub fn get_main_writer(&self) -> &LinkerWriter { + &self.main_writer + } + + #[must_use] + pub fn get_partial_writers(&self) -> &Vec { + &self.partial_writers + } +} diff --git a/slinky/src/settings.rs b/slinky/src/settings.rs index d0ecebe..7ca8bd4 100644 --- a/slinky/src/settings.rs +++ b/slinky/src/settings.rs @@ -27,6 +27,9 @@ pub struct Settings { pub sections_denylist: Vec, pub discard_wildcard_section: bool, + pub partial_scripts_path: Option, + pub partial_build_segments_path: Option, + // Options passed down to each segment pub alloc_sections: Vec, pub noload_sections: Vec, @@ -46,19 +49,19 @@ fn settings_default_base_path() -> PathBuf { PathBuf::new() } -fn settings_default_linker_symbols_style() -> LinkerSymbolsStyle { +const fn settings_default_linker_symbols_style() -> LinkerSymbolsStyle { LinkerSymbolsStyle::Splat } -fn settings_default_d_path() -> Option { +const fn settings_default_d_path() -> Option { None } -fn settings_default_target_path() -> Option { +const fn settings_default_target_path() -> Option { None } -fn settings_default_symbols_header_path() -> Option { +const fn settings_default_symbols_header_path() -> Option { None } @@ -66,15 +69,15 @@ fn settings_default_symbols_header_type() -> String { "char".to_string() } -fn settings_default_symbols_header_as_array() -> bool { +const fn settings_default_symbols_header_as_array() -> bool { true } -fn settings_default_hardcoded_gp_value() -> Option { +const fn settings_default_hardcoded_gp_value() -> Option { None } -fn settings_default_sections_allowlist() -> Vec { +const fn settings_default_sections_allowlist() -> Vec { vec![] } @@ -93,10 +96,18 @@ fn settings_default_sections_denylist() -> Vec { ] } -fn settings_default_discard_wildcard_section() -> bool { +const fn settings_default_discard_wildcard_section() -> bool { true } +const fn settings_default_partial_scripts_path() -> Option { + None +} + +const fn settings_default_partial_build_segments_path() -> Option { + None +} + fn settings_default_alloc_sections() -> Vec { vec![ ".text".into(), @@ -115,23 +126,23 @@ fn settings_default_noload_sections() -> Vec { ] } -fn settings_default_subalign() -> Option { +const fn settings_default_subalign() -> Option { Some(0x10) } -fn settings_default_segment_start_align() -> Option { +const fn settings_default_segment_start_align() -> Option { None } -fn settings_default_section_end_align() -> Option { +const fn settings_default_section_end_align() -> Option { Some(0x10) } -fn settings_default_wildcard_sections() -> bool { +const fn settings_default_wildcard_sections() -> bool { true } -fn settings_default_fill_value() -> Option { +const fn settings_default_fill_value() -> Option { Some(0) } @@ -155,6 +166,9 @@ impl Default for Settings { sections_denylist: settings_default_sections_denylist(), discard_wildcard_section: settings_default_discard_wildcard_section(), + partial_scripts_path: settings_default_partial_scripts_path(), + partial_build_segments_path: settings_default_partial_build_segments_path(), + alloc_sections: settings_default_alloc_sections(), noload_sections: settings_default_noload_sections(), @@ -201,6 +215,9 @@ pub(crate) struct SettingsSerial { #[serde(default)] pub discard_wildcard_section: AbsentNullable, + pub partial_scripts_path: AbsentNullable, + pub partial_build_segments_path: AbsentNullable, + // Options passed down to each Segment #[serde(default)] pub alloc_sections: AbsentNullable>, @@ -268,6 +285,15 @@ impl SettingsSerial { settings_default_discard_wildcard_section, )?; + let partial_scripts_path = self.partial_scripts_path.get_optional_nullable( + "partial_scripts_path", + settings_default_partial_scripts_path, + )?; + let partial_build_segments_path = self.partial_build_segments_path.get_optional_nullable( + "partial_build_segments_path", + settings_default_partial_build_segments_path, + )?; + if d_path.is_some() && target_path.is_none() { return Err(SlinkyError::MissingRequiredFieldCombo { required: "target_path".to_string(), @@ -318,6 +344,10 @@ impl SettingsSerial { sections_allowlist_extra, sections_denylist, discard_wildcard_section, + + partial_scripts_path, + partial_build_segments_path, + alloc_sections, noload_sections, subalign,