From 1fe9ec32ba359d48097b1f8beba4c2575fdd2b33 Mon Sep 17 00:00:00 2001 From: polybiusproxy <47796739+polybiusproxy@users.noreply.github.com> Date: Sat, 20 Dec 2025 15:04:16 +0100 Subject: [PATCH 1/3] Add option to control emission of `noload` segment --- CHANGELOG.md | 4 ++++ slinky/src/keep_sections.rs | 10 +++------- slinky/src/linker_writer.rs | 10 +++++++--- slinky/src/partial_linker_writer.rs | 8 ++++---- slinky/src/segment.rs | 10 +++++++++- slinky/src/settings.rs | 15 ++++++++++++++- 6 files changed, 41 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cae2b1..d183ea9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add option to control emission of `noload` segment. + ### Changed - Include `.symtab` and `.strtab` in default value of `sections_allowlist_extra` diff --git a/slinky/src/keep_sections.rs b/slinky/src/keep_sections.rs index 9d3261f..b1813c3 100644 --- a/slinky/src/keep_sections.rs +++ b/slinky/src/keep_sections.rs @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-FileCopyrightText: © 2025 decompals */ /* SPDX-License-Identifier: MIT */ use std::collections::HashSet; @@ -10,15 +10,11 @@ use serde::Deserialize; #[derive(Clone, Debug, Eq, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] +#[derive(Default)] pub enum KeepSections { #[serde(skip)] + #[default] Absent, All(bool), WhichOnes(HashSet), } - -impl Default for KeepSections { - fn default() -> Self { - Self::Absent - } -} diff --git a/slinky/src/linker_writer.rs b/slinky/src/linker_writer.rs index 1d84b3c..1d1642c 100644 --- a/slinky/src/linker_writer.rs +++ b/slinky/src/linker_writer.rs @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-FileCopyrightText: © 2025 decompals */ /* SPDX-License-Identifier: MIT */ use std::borrow::Cow; @@ -559,7 +559,9 @@ impl LinkerWriter<'_> { self.buffer.write_empty_line(); // Emit noload segment - self.write_segment(segment, &segment.noload_sections, true)?; + if segment.emit_noload_segment { + self.write_segment(segment, &segment.noload_sections, true)?; + } self.buffer.write_empty_line(); @@ -617,7 +619,9 @@ impl LinkerWriter<'_> { self.buffer.write_empty_line(); // Emit noload segment - self.write_single_segment(segment, &segment.noload_sections, true)?; + if segment.emit_noload_segment { + self.write_single_segment(segment, &segment.noload_sections, true)?; + } self.buffer.write_empty_line(); diff --git a/slinky/src/partial_linker_writer.rs b/slinky/src/partial_linker_writer.rs index 6a42536..147c090 100644 --- a/slinky/src/partial_linker_writer.rs +++ b/slinky/src/partial_linker_writer.rs @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-FileCopyrightText: © 2025 decompals */ /* SPDX-License-Identifier: MIT */ use crate::{ @@ -64,7 +64,7 @@ impl ScriptImporter for PartialLinkerWriter<'_> { let mut p = partial_build_segments_folder.clone(); - p.push(&format!("{}.o", segment.name)); + p.push(format!("{}.o", segment.name)); self.main_writer .add_segment(&segment.clone_with_new_files(vec![FileInfo::new_object(p)]))?; @@ -186,12 +186,12 @@ impl ScriptGenerator for PartialLinkerWriter<'_> {} // Getters / Setters impl PartialLinkerWriter<'_> { #[must_use] - pub fn get_main_writer(&self) -> &LinkerWriter { + pub fn get_main_writer(&self) -> &LinkerWriter<'_> { &self.main_writer } #[must_use] - pub fn get_partial_writers(&self) -> &Vec<(LinkerWriter, String)> { + pub fn get_partial_writers(&self) -> &Vec<(LinkerWriter<'_>, String)> { &self.partial_writers } } diff --git a/slinky/src/segment.rs b/slinky/src/segment.rs index 08e5760..354273d 100644 --- a/slinky/src/segment.rs +++ b/slinky/src/segment.rs @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-FileCopyrightText: © 2025 decompals */ /* SPDX-License-Identifier: MIT */ use std::{borrow::Cow, collections::HashMap, path::PathBuf}; @@ -50,6 +50,7 @@ pub struct Segment { // The default value of the following members come from Settings pub alloc_sections: Vec, pub noload_sections: Vec, + pub emit_noload_segment: bool, pub subalign: Option, pub segment_start_align: Option, @@ -86,6 +87,7 @@ impl Segment { exclude_if_all: self.exclude_if_all.clone(), alloc_sections: self.alloc_sections.clone(), noload_sections: self.noload_sections.clone(), + emit_noload_segment: self.emit_noload_segment, subalign: self.subalign, segment_start_align: self.segment_start_align, segment_end_align: self.segment_end_align, @@ -159,6 +161,8 @@ pub(crate) struct SegmentSerial { pub alloc_sections: AbsentNullable>, #[serde(default)] pub noload_sections: AbsentNullable>, + #[serde(default)] + pub emit_noload_segment: AbsentNullable, #[serde(default)] pub subalign: AbsentNullable, @@ -297,6 +301,9 @@ impl Serial for SegmentSerial { let noload_sections = self .noload_sections .get_non_null("noload_sections", || settings.noload_sections.clone())?; + let emit_noload_segment = self + .emit_noload_segment + .get_non_null("emit_noload_segment", || settings.emit_noload_segment)?; if let Some(gp) = &gp_info { if !alloc_sections.contains(&gp.section) && !noload_sections.contains(&gp.section) { @@ -376,6 +383,7 @@ impl Serial for SegmentSerial { exclude_if_all, alloc_sections, noload_sections, + emit_noload_segment, subalign, segment_start_align, segment_end_align, diff --git a/slinky/src/settings.rs b/slinky/src/settings.rs index b3e5fd3..1187158 100644 --- a/slinky/src/settings.rs +++ b/slinky/src/settings.rs @@ -1,4 +1,4 @@ -/* SPDX-FileCopyrightText: © 2024 decompals */ +/* SPDX-FileCopyrightText: © 2025 decompals */ /* SPDX-License-Identifier: MIT */ use serde::Deserialize; @@ -36,6 +36,7 @@ pub struct Settings { // Options passed down to each segment pub alloc_sections: Vec, pub noload_sections: Vec, + pub emit_noload_segment: bool, pub subalign: Option, pub segment_start_align: Option, @@ -138,6 +139,10 @@ fn settings_default_noload_sections() -> Vec { ] } +const fn settings_default_emit_noload_segment() -> bool { + true +} + const fn settings_default_subalign() -> Option { None } @@ -205,6 +210,7 @@ impl Default for Settings { alloc_sections: settings_default_alloc_sections(), noload_sections: settings_default_noload_sections(), + emit_noload_segment: settings_default_emit_noload_segment(), subalign: settings_default_subalign(), segment_start_align: settings_default_segment_start_align(), @@ -321,6 +327,8 @@ pub(crate) struct SettingsSerial { pub alloc_sections: AbsentNullable>, #[serde(default)] pub noload_sections: AbsentNullable>, + #[serde(default)] + pub emit_noload_segment: AbsentNullable, #[serde(default)] pub subalign: AbsentNullable, @@ -421,6 +429,9 @@ impl SettingsSerial { let noload_sections = self .noload_sections .get_non_null("noload_sections", settings_default_noload_sections)?; + let emit_noload_segment = self + .emit_noload_segment + .get_non_null("emit_noload_segment", settings_default_emit_noload_segment)?; let subalign = self .subalign @@ -488,6 +499,8 @@ impl SettingsSerial { alloc_sections, noload_sections, + emit_noload_segment, + subalign, segment_start_align, segment_end_align, From 5e1ed5146d5c561caca4b08f1c2b1e39b9cf23d5 Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Sun, 19 Apr 2026 19:55:44 -0400 Subject: [PATCH 2/3] Rework alloc_sections and noload_sections to accept null. Also remove emit_noload_segment --- docs/file_format/segments.md | 11 +- docs/file_format/settings.md | 11 +- slinky/src/keep_sections.rs | 2 - slinky/src/linker_writer.rs | 16 ++- slinky/src/segment.rs | 22 ++-- slinky/src/settings.rs | 32 ++--- slinky/src/utils.rs | 10 ++ tests/test_cases/null_sections.h | 83 ++++++++++++ tests/test_cases/null_sections.ld | 194 ++++++++++++++++++++++++++++ tests/test_cases/null_sections.yaml | 25 ++++ 10 files changed, 358 insertions(+), 48 deletions(-) create mode 100644 tests/test_cases/null_sections.h create mode 100644 tests/test_cases/null_sections.ld create mode 100644 tests/test_cases/null_sections.yaml diff --git a/docs/file_format/segments.md b/docs/file_format/segments.md index 89a6cf1..c95244c 100644 --- a/docs/file_format/segments.md +++ b/docs/file_format/segments.md @@ -295,6 +295,10 @@ segment. The sections from this list will be emitted for each file in the specified order. +A `null` value can be used to signal that no allocatable sections should be +emitted for this segment. Setting to `null` will avoid emitting linker symbols +for allocatable sections too. + This allows to override the global settings in case a specific segment has an order different than the global one. See [settings.md#alloc_sections](settings.md#alloc_sections) for more info. @@ -308,7 +312,7 @@ settings: ### Valid values -List of strings. +List of strings or `null`. ### Default value @@ -322,6 +326,9 @@ segment. The sections from this list will be emitted for each file in the specified order. +A `null` value can be used to signal that no noload sections should be emitted. +Setting to `null` will avoid emitting linker symbols for noload sections too. + This allows to override the global settings in case a specific segment has an order different than the global one. See [settings.md#noload_sections](settings.md#noload_sections) for more info. @@ -335,7 +342,7 @@ settings: ### Valid values -List of strings. +List of strings or `null`. ### Default value diff --git a/docs/file_format/settings.md b/docs/file_format/settings.md index 3ab9969..8dc625c 100644 --- a/docs/file_format/settings.md +++ b/docs/file_format/settings.md @@ -536,6 +536,10 @@ List of allocatable sections (the ones that take ROM space). The sections from this list will be emitted for each file in the specified order. +A `null` value can be used to signal that no allocatable sections should be +emitted. Setting to `null` will avoid emitting linker symbols for allocatable +sections too. + This option can be overriden per segment, see [segments.md#alloc_sections](segments.md#alloc_sections) for more info. @@ -548,7 +552,7 @@ settings: ### Valid values -List of strings. +List of strings or `null`. ### Default value @@ -561,6 +565,9 @@ List of noload sections (the ones that don't take ROM space). The sections from this list will be emitted for each file in the specified order. +A `null` value can be used to signal that no noload sections should be emitted. +Setting to `null` will avoid emitting linker symbols for noload sections too. + This option can be overriden per segment, see [segments.md#noload_sections](segments.md#noload_sections) for more info. @@ -573,7 +580,7 @@ settings: ### Valid values -List of strings. +List of strings or `null`. ### Default value diff --git a/slinky/src/keep_sections.rs b/slinky/src/keep_sections.rs index f2fe46e..01da68d 100644 --- a/slinky/src/keep_sections.rs +++ b/slinky/src/keep_sections.rs @@ -10,11 +10,9 @@ use serde::Deserialize; #[derive(Debug, Clone, PartialEq, Eq, Default, Deserialize)] #[serde(deny_unknown_fields)] #[serde(untagged)] -#[derive(Default)] pub enum KeepSections { #[default] #[serde(skip)] - #[default] Absent, All(bool), WhichOnes(HashSet), diff --git a/slinky/src/linker_writer.rs b/slinky/src/linker_writer.rs index f40247a..2480d0d 100644 --- a/slinky/src/linker_writer.rs +++ b/slinky/src/linker_writer.rs @@ -554,13 +554,15 @@ impl LinkerWriter<'_> { .write_linker_symbol(&main_seg_sym_start, &format!("ADDR(.{})", segment.name)); // Emit alloc segment - self.write_segment(segment, &segment.alloc_sections, false)?; + if let Some(alloc_sections) = &segment.alloc_sections { + self.write_segment(segment, alloc_sections, false)?; + } self.buffer.write_empty_line(); // Emit noload segment - if segment.emit_noload_segment { - self.write_segment(segment, &segment.noload_sections, true)?; + if let Some(noload_sections) = &segment.noload_sections { + self.write_segment(segment, noload_sections, true)?; } self.buffer.write_empty_line(); @@ -614,13 +616,15 @@ impl LinkerWriter<'_> { } // Emit alloc segment - self.write_single_segment(segment, &segment.alloc_sections, false)?; + if let Some(alloc_sections) = &segment.alloc_sections { + self.write_single_segment(segment, alloc_sections, false)?; + } self.buffer.write_empty_line(); // Emit noload segment - if segment.emit_noload_segment { - self.write_single_segment(segment, &segment.noload_sections, true)?; + if let Some(noload_sections) = &segment.noload_sections { + self.write_single_segment(segment, noload_sections, true)?; } self.buffer.write_empty_line(); diff --git a/slinky/src/segment.rs b/slinky/src/segment.rs index 11174e4..5a09d5f 100644 --- a/slinky/src/segment.rs +++ b/slinky/src/segment.rs @@ -10,7 +10,7 @@ use crate::{ file_info::{FileInfo, FileInfoSerial}, gp_info::{GpInfo, GpInfoSerial}, traits::Serial, - EscapedPath, KeepSections, RuntimeSettings, Settings, SlinkyError, + utils, EscapedPath, KeepSections, RuntimeSettings, Settings, SlinkyError, }; #[derive(PartialEq, Debug, Clone)] @@ -48,9 +48,8 @@ pub struct Segment { pub exclude_if_all: Vec<(String, String)>, // The default value of the following members come from Settings - pub alloc_sections: Vec, - pub noload_sections: Vec, - pub emit_noload_segment: bool, + pub alloc_sections: Option>, + pub noload_sections: Option>, pub subalign: Option, pub segment_start_align: Option, @@ -87,7 +86,6 @@ impl Segment { exclude_if_all: self.exclude_if_all.clone(), alloc_sections: self.alloc_sections.clone(), noload_sections: self.noload_sections.clone(), - emit_noload_segment: self.emit_noload_segment, subalign: self.subalign, segment_start_align: self.segment_start_align, segment_end_align: self.segment_end_align, @@ -161,8 +159,6 @@ pub(crate) struct SegmentSerial { pub alloc_sections: AbsentNullable>, #[serde(default)] pub noload_sections: AbsentNullable>, - #[serde(default)] - pub emit_noload_segment: AbsentNullable, #[serde(default)] pub subalign: AbsentNullable, @@ -297,16 +293,15 @@ impl Serial for SegmentSerial { let alloc_sections = self .alloc_sections - .get_non_null("alloc_sections", || settings.alloc_sections.clone())?; + .get_optional_nullable("alloc_sections", || settings.alloc_sections.clone())?; let noload_sections = self .noload_sections - .get_non_null("noload_sections", || settings.noload_sections.clone())?; - let emit_noload_segment = self - .emit_noload_segment - .get_non_null("emit_noload_segment", || settings.emit_noload_segment)?; + .get_optional_nullable("noload_sections", || settings.noload_sections.clone())?; if let Some(gp) = &gp_info { - if !alloc_sections.contains(&gp.section) && !noload_sections.contains(&gp.section) { + if utils::is_none_or(alloc_sections.as_ref(), |s| !s.contains(&gp.section)) + && utils::is_none_or(noload_sections.as_ref(), |s| !s.contains(&gp.section)) + { return Err(SlinkyError::MissingSectionForSegment { field_name: Cow::from("gp_info"), section: Cow::from(gp_info.unwrap().section), @@ -383,7 +378,6 @@ impl Serial for SegmentSerial { exclude_if_all, alloc_sections, noload_sections, - emit_noload_segment, subalign, segment_start_align, segment_end_align, diff --git a/slinky/src/settings.rs b/slinky/src/settings.rs index e50d334..49670b5 100644 --- a/slinky/src/settings.rs +++ b/slinky/src/settings.rs @@ -34,9 +34,8 @@ pub struct Settings { pub partial_build_segments_folder: Option, // Options passed down to each segment - pub alloc_sections: Vec, - pub noload_sections: Vec, - pub emit_noload_segment: bool, + pub alloc_sections: Option>, + pub noload_sections: Option>, pub subalign: Option, pub segment_start_align: Option, @@ -121,26 +120,22 @@ const fn settings_default_partial_build_segments_folder() -> Option { None } -fn settings_default_alloc_sections() -> Vec { - vec![ +fn settings_default_alloc_sections() -> Option> { + Some(vec![ ".text".into(), ".data".into(), ".rodata".into(), ".sdata".into(), - ] + ]) } -fn settings_default_noload_sections() -> Vec { - vec![ +fn settings_default_noload_sections() -> Option> { + Some(vec![ ".sbss".into(), ".scommon".into(), ".bss".into(), "COMMON".into(), - ] -} - -const fn settings_default_emit_noload_segment() -> bool { - true + ]) } const fn settings_default_subalign() -> Option { @@ -210,7 +205,6 @@ impl Default for Settings { alloc_sections: settings_default_alloc_sections(), noload_sections: settings_default_noload_sections(), - emit_noload_segment: settings_default_emit_noload_segment(), subalign: settings_default_subalign(), segment_start_align: settings_default_segment_start_align(), @@ -327,8 +321,6 @@ pub(crate) struct SettingsSerial { pub alloc_sections: AbsentNullable>, #[serde(default)] pub noload_sections: AbsentNullable>, - #[serde(default)] - pub emit_noload_segment: AbsentNullable, #[serde(default)] pub subalign: AbsentNullable, @@ -425,13 +417,10 @@ impl SettingsSerial { let alloc_sections = self .alloc_sections - .get_non_null("alloc_sections", settings_default_alloc_sections)?; + .get_optional_nullable("alloc_sections", settings_default_alloc_sections)?; let noload_sections = self .noload_sections - .get_non_null("noload_sections", settings_default_noload_sections)?; - let emit_noload_segment = self - .emit_noload_segment - .get_non_null("emit_noload_segment", settings_default_emit_noload_segment)?; + .get_optional_nullable("noload_sections", settings_default_noload_sections)?; let subalign = self .subalign @@ -499,7 +488,6 @@ impl SettingsSerial { alloc_sections, noload_sections, - emit_noload_segment, subalign, segment_start_align, diff --git a/slinky/src/utils.rs b/slinky/src/utils.rs index f982ca8..b2658ce 100644 --- a/slinky/src/utils.rs +++ b/slinky/src/utils.rs @@ -37,3 +37,13 @@ pub(crate) fn create_file_and_parents(path: &Path) -> Result }), } } + +pub(crate) fn is_none_or(val: Option<&T>, f: F) -> bool +where + F: FnOnce(&T) -> bool, +{ + match val { + None => true, + Some(x) => f(x), + } +} diff --git a/tests/test_cases/null_sections.h b/tests/test_cases/null_sections.h new file mode 100644 index 0000000..1008189 --- /dev/null +++ b/tests/test_cases/null_sections.h @@ -0,0 +1,83 @@ +#ifndef HEADER_SYMBOLS_H +#define HEADER_SYMBOLS_H + +extern char boot_ROM_START[]; +extern char boot_VRAM[]; +extern char boot_alloc_VRAM[]; +extern char boot_TEXT_START[]; +extern char boot_TEXT_END[]; +extern char boot_TEXT_SIZE[]; +extern char boot_DATA_START[]; +extern char boot_DATA_END[]; +extern char boot_DATA_SIZE[]; +extern char boot_RODATA_START[]; +extern char boot_RODATA_END[]; +extern char boot_RODATA_SIZE[]; +extern char boot_SDATA_START[]; +extern char boot_SDATA_END[]; +extern char boot_SDATA_SIZE[]; +extern char boot_alloc_VRAM_END[]; +extern char boot_alloc_VRAM_SIZE[]; +extern char boot_noload_VRAM[]; +extern char boot_SBSS_START[]; +extern char boot_SBSS_END[]; +extern char boot_SBSS_SIZE[]; +extern char boot_SCOMMON_START[]; +extern char boot_SCOMMON_END[]; +extern char boot_SCOMMON_SIZE[]; +extern char boot_BSS_START[]; +extern char boot_BSS_END[]; +extern char boot_BSS_SIZE[]; +extern char bootCOMMON_START[]; +extern char bootCOMMON_END[]; +extern char bootCOMMON_SIZE[]; +extern char boot_noload_VRAM_END[]; +extern char boot_noload_VRAM_SIZE[]; +extern char boot_VRAM_END[]; +extern char boot_VRAM_SIZE[]; +extern char boot_ROM_END[]; +extern char boot_ROM_SIZE[]; +extern char buffers_ROM_START[]; +extern char buffers_VRAM[]; +extern char buffers_noload_VRAM[]; +extern char buffers_SBSS_START[]; +extern char buffers_SBSS_END[]; +extern char buffers_SBSS_SIZE[]; +extern char buffers_SCOMMON_START[]; +extern char buffers_SCOMMON_END[]; +extern char buffers_SCOMMON_SIZE[]; +extern char buffers_BSS_START[]; +extern char buffers_BSS_END[]; +extern char buffers_BSS_SIZE[]; +extern char buffersCOMMON_START[]; +extern char buffersCOMMON_END[]; +extern char buffersCOMMON_SIZE[]; +extern char buffers_noload_VRAM_END[]; +extern char buffers_noload_VRAM_SIZE[]; +extern char buffers_VRAM_END[]; +extern char buffers_VRAM_SIZE[]; +extern char buffers_ROM_END[]; +extern char buffers_ROM_SIZE[]; +extern char assets_ROM_START[]; +extern char assets_VRAM[]; +extern char assets_alloc_VRAM[]; +extern char assets_TEXT_START[]; +extern char assets_TEXT_END[]; +extern char assets_TEXT_SIZE[]; +extern char assets_DATA_START[]; +extern char assets_DATA_END[]; +extern char assets_DATA_SIZE[]; +extern char assets_RODATA_START[]; +extern char assets_RODATA_END[]; +extern char assets_RODATA_SIZE[]; +extern char assets_SDATA_START[]; +extern char assets_SDATA_END[]; +extern char assets_SDATA_SIZE[]; +extern char assets_alloc_VRAM_END[]; +extern char assets_alloc_VRAM_SIZE[]; +extern char assets_VRAM_END[]; +extern char assets_VRAM_SIZE[]; +extern char assets_ROM_END[]; +extern char assets_ROM_SIZE[]; + +#endif diff --git a/tests/test_cases/null_sections.ld b/tests/test_cases/null_sections.ld new file mode 100644 index 0000000..87e47df --- /dev/null +++ b/tests/test_cases/null_sections.ld @@ -0,0 +1,194 @@ +SECTIONS +{ + __romPos = 0x0; + + boot_ROM_START = __romPos; + boot_VRAM = ADDR(.boot); + boot_alloc_VRAM = .; + + .boot : AT(boot_ROM_START) + { + FILL(0x00000000); + boot_TEXT_START = .; + build/src/boot_main.o(.text*); + build/src/dmadata.o(.text*); + build/asm/util.o(.text*); + boot_TEXT_END = .; + boot_TEXT_SIZE = ABSOLUTE(boot_TEXT_END - boot_TEXT_START); + + boot_DATA_START = .; + build/src/boot_main.o(.data*); + build/src/dmadata.o(.data*); + build/asm/util.o(.data*); + boot_DATA_END = .; + boot_DATA_SIZE = ABSOLUTE(boot_DATA_END - boot_DATA_START); + + boot_RODATA_START = .; + build/src/boot_main.o(.rodata*); + build/src/dmadata.o(.rodata*); + build/asm/util.o(.rodata*); + boot_RODATA_END = .; + boot_RODATA_SIZE = ABSOLUTE(boot_RODATA_END - boot_RODATA_START); + + boot_SDATA_START = .; + build/src/boot_main.o(.sdata*); + build/src/dmadata.o(.sdata*); + build/asm/util.o(.sdata*); + boot_SDATA_END = .; + boot_SDATA_SIZE = ABSOLUTE(boot_SDATA_END - boot_SDATA_START); + } + + boot_alloc_VRAM_END = .; + boot_alloc_VRAM_SIZE = ABSOLUTE(boot_alloc_VRAM_END - boot_alloc_VRAM); + + boot_noload_VRAM = .; + + .boot.noload (NOLOAD) : + { + FILL(0x00000000); + boot_SBSS_START = .; + build/src/boot_main.o(.sbss*); + build/src/dmadata.o(.sbss*); + build/asm/util.o(.sbss*); + boot_SBSS_END = .; + boot_SBSS_SIZE = ABSOLUTE(boot_SBSS_END - boot_SBSS_START); + + boot_SCOMMON_START = .; + build/src/boot_main.o(.scommon*); + build/src/dmadata.o(.scommon*); + build/asm/util.o(.scommon*); + boot_SCOMMON_END = .; + boot_SCOMMON_SIZE = ABSOLUTE(boot_SCOMMON_END - boot_SCOMMON_START); + + boot_BSS_START = .; + build/src/boot_main.o(.bss*); + build/src/dmadata.o(.bss*); + build/asm/util.o(.bss*); + boot_BSS_END = .; + boot_BSS_SIZE = ABSOLUTE(boot_BSS_END - boot_BSS_START); + + bootCOMMON_START = .; + build/src/boot_main.o(COMMON*); + build/src/dmadata.o(COMMON*); + build/asm/util.o(COMMON*); + bootCOMMON_END = .; + bootCOMMON_SIZE = ABSOLUTE(bootCOMMON_END - bootCOMMON_START); + } + + boot_noload_VRAM_END = .; + boot_noload_VRAM_SIZE = ABSOLUTE(boot_noload_VRAM_END - boot_noload_VRAM); + + __romPos += SIZEOF(.boot); + boot_VRAM_END = .; + boot_VRAM_SIZE = ABSOLUTE(boot_VRAM_END - boot_VRAM); + boot_ROM_END = __romPos; + boot_ROM_SIZE = ABSOLUTE(boot_ROM_END - boot_ROM_START); + + buffers_ROM_START = __romPos; + buffers_VRAM = ADDR(.buffers); + + buffers_noload_VRAM = .; + + .buffers.noload (NOLOAD) : + { + FILL(0x00000000); + buffers_SBSS_START = .; + build/src/arenabuffer.o(.sbss*); + build/src/scratchpad.o(.sbss*); + build/src/framebuffer.o(.sbss*); + buffers_SBSS_END = .; + buffers_SBSS_SIZE = ABSOLUTE(buffers_SBSS_END - buffers_SBSS_START); + + buffers_SCOMMON_START = .; + build/src/arenabuffer.o(.scommon*); + build/src/scratchpad.o(.scommon*); + build/src/framebuffer.o(.scommon*); + buffers_SCOMMON_END = .; + buffers_SCOMMON_SIZE = ABSOLUTE(buffers_SCOMMON_END - buffers_SCOMMON_START); + + buffers_BSS_START = .; + build/src/arenabuffer.o(.bss*); + build/src/scratchpad.o(.bss*); + build/src/framebuffer.o(.bss*); + buffers_BSS_END = .; + buffers_BSS_SIZE = ABSOLUTE(buffers_BSS_END - buffers_BSS_START); + + buffersCOMMON_START = .; + build/src/arenabuffer.o(COMMON*); + build/src/scratchpad.o(COMMON*); + build/src/framebuffer.o(COMMON*); + buffersCOMMON_END = .; + buffersCOMMON_SIZE = ABSOLUTE(buffersCOMMON_END - buffersCOMMON_START); + } + + buffers_noload_VRAM_END = .; + buffers_noload_VRAM_SIZE = ABSOLUTE(buffers_noload_VRAM_END - buffers_noload_VRAM); + + __romPos += SIZEOF(.buffers); + buffers_VRAM_END = .; + buffers_VRAM_SIZE = ABSOLUTE(buffers_VRAM_END - buffers_VRAM); + buffers_ROM_END = __romPos; + buffers_ROM_SIZE = ABSOLUTE(buffers_ROM_END - buffers_ROM_START); + + assets_ROM_START = __romPos; + assets_VRAM = ADDR(.assets); + assets_alloc_VRAM = .; + + .assets : AT(assets_ROM_START) + { + FILL(0x00000000); + assets_TEXT_START = .; + build/src/font.o(.text*); + build/src/music.o(.text*); + build/src/videos.o(.text*); + assets_TEXT_END = .; + assets_TEXT_SIZE = ABSOLUTE(assets_TEXT_END - assets_TEXT_START); + + assets_DATA_START = .; + build/src/font.o(.data*); + build/src/music.o(.data*); + build/src/videos.o(.data*); + assets_DATA_END = .; + assets_DATA_SIZE = ABSOLUTE(assets_DATA_END - assets_DATA_START); + + assets_RODATA_START = .; + build/src/font.o(.rodata*); + build/src/music.o(.rodata*); + build/src/videos.o(.rodata*); + assets_RODATA_END = .; + assets_RODATA_SIZE = ABSOLUTE(assets_RODATA_END - assets_RODATA_START); + + assets_SDATA_START = .; + build/src/font.o(.sdata*); + build/src/music.o(.sdata*); + build/src/videos.o(.sdata*); + assets_SDATA_END = .; + assets_SDATA_SIZE = ABSOLUTE(assets_SDATA_END - assets_SDATA_START); + } + + assets_alloc_VRAM_END = .; + assets_alloc_VRAM_SIZE = ABSOLUTE(assets_alloc_VRAM_END - assets_alloc_VRAM); + + + __romPos += SIZEOF(.assets); + assets_VRAM_END = .; + assets_VRAM_SIZE = ABSOLUTE(assets_VRAM_END - assets_VRAM); + assets_ROM_END = __romPos; + assets_ROM_SIZE = ABSOLUTE(assets_ROM_END - assets_ROM_START); + + .symtab 0 : { *(.symtab); } + .strtab 0 : { *(.strtab); } + .shstrtab 0 : { *(.shstrtab); } + + /DISCARD/ : + { + *(.reginfo); + *(.MIPS.abiflags); + *(.MIPS.options); + *(.note.gnu.build-id); + *(.interp); + *(.eh_frame); + *(.got); + *(*); + } +} diff --git a/tests/test_cases/null_sections.yaml b/tests/test_cases/null_sections.yaml new file mode 100644 index 0000000..cce7d55 --- /dev/null +++ b/tests/test_cases/null_sections.yaml @@ -0,0 +1,25 @@ +settings: + base_path: build + symbols_header_path: tests/test_cases/null_sections.h + +segments: + + - name: boot + files: + - { path: src/boot_main.o } + - { path: src/dmadata.o } + - { path: asm/util.o } + + - name: buffers + alloc_sections: null + files: + - { path: src/arenabuffer.o } + - { path: src/scratchpad.o } + - { path: src/framebuffer.o } + + - name: assets + noload_sections: null + files: + - { path: src/font.o } + - { path: src/music.o } + - { path: src/videos.o } From 7bc87ac2b364e8cbaf487211eeb3312341a491ea Mon Sep 17 00:00:00 2001 From: Anghelo Carvajal Date: Sun, 19 Apr 2026 20:01:48 -0400 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d183ea9..e290b4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added - - Add option to control emission of `noload` segment. ### Changed @@ -19,6 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 explicitly on the linker script. - Add `.got` to the default list of discarded sections. - Simplify the formatting used for extra sections. +- `alloc_sections` and `noload_sections` sections now accept `null` values. + - This allows to avoid emitting those sections completely for a given segment + or globally. + - The main difference between using `null` and an empty list is `null` will + not produce linker symbol nor the section itself in the generated linker + script, while the empty list would generate the starting and ending linker + symbols and the section with no files. ## [0.3.0] - 2024-08-17