Skip to content

Commit

Permalink
Add KEEP support
Browse files Browse the repository at this point in the history
Closes #61
  • Loading branch information
AngheloAlf committed Aug 16, 2024
1 parent 0fc55bb commit 0fc03a2
Show file tree
Hide file tree
Showing 24 changed files with 653 additions and 168 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add new top-level attribute for the file format: `asserts`.
- Allows to define multiple assertions that should be satisfied for the link
to success.
- New `keep_sections` attribute for `vram_classes`, `segments` and `files`.
- Allows to specify which sections of a files should be `KEEP` during link
time garbage collection, even of those are not referenced at al by anything
else.
- Allows to configure for everything referencing a given vram class or as
fine grained as a single file entry.

### Changed

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ extra shiftability features not present on other tools.
- Support for defining a shiftable `_gp` for small data support.
- Support for defining the entrypoint of the executable.
- Support for defining asserts to ensure the sanity of the build.
- Support emitting `KEEP`s attributes for file entries, allowing for a more
flexible link time garbage collection.

### Planned features

Expand Down
81 changes: 81 additions & 0 deletions docs/file_format/file.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ Every attribute listed is optional unless explicitly stated.
- [`exclude_if_all`](#exclude_if_all)
- [Example](#example-10)
- [Valid values](#valid-values-10)
- [`keep_sections`](#keep_sections)
- [Example](#example-11)
- [Valid values](#valid-values-11)
- [Default](#default-1)

## `path`

Expand Down Expand Up @@ -428,3 +432,80 @@ segments:
### Valid values
A non-empty list of two-tuples of strings.
## `keep_sections`

Wraps the sections of this file with `KEEP` attributes.

`KEEP` is only relevant when link time garbage collection is enabled (the
[`--gc-sections`](https://sourceware.org/binutils/docs/ld/Options.html#index-garbage-collection)
flag of GNU LD), since wrapping a section with a `KEEP` attribute tells the
linker that this section should not be garbage collected, even if none of the
symbols on that section is referenced by anything else that is actually used.

If link time garbage collection is enabled then it is recommended to set the
entrypoint of this program by setting the slinky top-level attribute `entry`.

The `keep_sections` attribute allow specify if _all_ the input sections (say
`.text`, `.data`, etc) of a given file entry should be wrapped by `KEEP` or not.
Alternatively a list of strings may be provided instead to specify which
specific sections should be wrapped with `KEEP`, allowing for a more fine
grained customization of this behavior.

If this entry happen to be a [group `kind`](#kind) then all the files listed on
this group that do not specify their own `keep_sections` will inherit it from
this entry instead, propagating this setting to all those file entries and
allowing the user to avoid unnecessary duplication.

If no `keep_sections` is specified for the current file entry, then the entry
will inherit it from `keep_section` of the [segment](segments.md) or
[file group](#kind) which contains this entry.

GNU LD documentation for
[`KEEP`](https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#index-KEEP).

### Example

```yaml
segments:
- name: main_segment
keep_sections: [.text]
files:
- kind: group
dir: src/rsp
keep_sections: True
files:
# Will `KEEP` every section
- { path: rspboot.o }
- { path: aspMain.o }
- { path: f3dex2.o }

- kind: group
dir: src/stufsh
keep_sections: [.data]
files:
- kind: group
files:
- { path: thingy1.o, keep_sections: [.text] } # Only `KEEP`s `.text`
- { path: thingy2.o } # Only `KEEP`s `.data`
- kind: group
keep_sections: [.rodata, .data]
files:
- kind: group
files:
- { path: thonga3.o } # `KEEP`s `.data` and `.rodata`
- { path: capy4.o } # `KEEP`s `.data` and `.rodata`
- { path: placeholder5.o, keep_sections: [.bss] } # Only `KEEP`s `.bss`
- { path: idk6.o, keep_sections: [.bss] } # Only `KEEP`s `.bss`
- { path: another7.o } # Only `KEEP`s `.data`
```
### Valid values
Either a boolean or a list of sections (list of strings).
### Default
The [`keep_sections` of the `segment` holding this entry](segments.md#keep_sections)
or the [`keep_sections` of the group `file` entry holding this entry](file.md#keep_sections)
or `False` if no inheritable property is found.
72 changes: 72 additions & 0 deletions docs/file_format/segments.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ Every attribute listed is optional unless explicitly stated.
- [Example](#example-18)
- [Valid values](#valid-values-16)
- [Default value](#default-value-15)
- [`keep_sections`](#keep_sections)
- [Example](#example-19)
- [Valid values](#valid-values-17)
- [Default](#default)

## `name`

Expand Down Expand Up @@ -603,3 +607,71 @@ Positive integers or `null`.
### Default value

The value specified for [settings.md#fill_value](settings.md#fill_value)

## `keep_sections`

Wraps the file entries from this current segment with `KEEP` attributes.

`KEEP` is only relevant when link time garbage collection is enabled (the
[`--gc-sections`](https://sourceware.org/binutils/docs/ld/Options.html#index-garbage-collection)
flag of GNU LD), since wrapping a section with a `KEEP` attribute tells the
linker that this section should not be garbage collected, even if none of the
symbols on that section is referenced by anything else that is actually used.

If link time garbage collection is enabled then it is recommended to set the
entrypoint of this program by setting the slinky top-level attribute `entry`.

The `keep_sections` attribute allow specify if _all_ the input sections (say
`.text`, `.data`, etc) of a given file entry should be wrapped by `KEEP` or not.
Alternatively a list of strings may be provided instead to specify which
specific sections should be wrapped with `KEEP`, allowing for a more fine
grained customization of this behavior.

Every file entry of the current segment will inherit its `keep_sections`
attribute, propagating this setting to all those file entries and allowing the
user to avoid unnecessary duplication. This setting may be overriden for
specific file entries of this segment. See specifying a
[`keep_sections` attribute on the `file` document](file.md#keep_sections)
for more information.

If no `keep_sections` is specified for the current segment, then the
`keep_section` of the corresponding [`vram class`](#vram_class) referenced by
this segment will be inherited automatically if any vram class was specified
for this segment.

GNU LD documentation for
[`KEEP`](https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#index-KEEP).

### Example

```yaml
segments:
- name: boot
keep_sections: [.data, .text]
files:
- { path: src/boot/boot_main.o }
- { path: src/boot/util.o, keep_sections: [.text, .rodata] }
- name: assets1
keep_sections: True
files:
- { path: src/assets/texture.o }
- { path: src/assets/dlist.o }
```

In the above example the `boot` segment says that the `.text` and `.data`
sections of the files within itself should be wrapped in `KEEP`s, which will be
true for the `boot_main.o` file. But for `util.o` the `.text` and `.rodata`
sections will be `KEEP`'d, not the `.data` section, completely overriding the
attribute set at the segment level.

The `assets1` segment sets every section of every of its files to be `KEEP`'d.

### Valid values

Either a boolean or a list of sections (list of strings).

### Default

The [`keep_sections` attribute of the corresponding `vram class`](vram_classes.md#keep_sections)
or `False` if this segment references no vram class.
86 changes: 86 additions & 0 deletions docs/file_format/vram_classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ to how segments have linker symbols for their start, end and size. See
- [`follow_classes`](#follow_classes)
- [Example](#example-3)
- [Valid values](#valid-values-3)
- [`keep_sections`](#keep_sections)
- [Example](#example-4)
- [Valid values](#valid-values-4)
- [Default](#default)

## `name`

Expand Down Expand Up @@ -220,3 +224,85 @@ TODO: Add images to explain this memory layout visually.
### Valid values
A list of strings. The strings must be names of existing vram classes.
## `keep_sections`
Wraps the file entries from the segments that reference this vram class with
`KEEP` attributes.
`KEEP` is only relevant when link time garbage collection is enabled (the
[`--gc-sections`](https://sourceware.org/binutils/docs/ld/Options.html#index-garbage-collection)
flag of GNU LD), since wrapping a section with a `KEEP` attribute tells the
linker that this section should not be garbage collected, even if none of the
symbols on that section is referenced by anything else that is actually used.
If link time garbage collection is enabled then it is recommended to set the
entrypoint of this program by setting the slinky top-level attribute `entry`.
The `keep_sections` attribute allow specify if _all_ the input sections (say
`.text`, `.data`, etc) of a given file entry should be wrapped by `KEEP` or not.
Alternatively a list of strings may be provided instead to specify which
specific sections should be wrapped with `KEEP`, allowing for a more fine
grained customization of this behavior.
Every segment referencing a vram class will inherit its `keep_sections`
attribute, propagating this setting to all those segments and allowing the user
to avoid unnecessary duplication. This setting may be overriden for specific
segments that still want to reference the given vram class. See specifying a
[`keep_sections` attribute on the `segments` document](segments.md#keep_sections)
for more information.
GNU LD documentation for
[`KEEP`](https://sourceware.org/binutils/docs/ld/Input-Section-Keep.html#index-KEEP).
### Example
```yaml
vram_classes:
- { name: battle_partner, fixed_vram: 0x80238000, keep_sections: [.text] }
- { name: segment_05, fixed_vram: 0x05000000, keep_sections: True }
segments:
- name: battle_partner_goompa
vram_class: battle_partner
files:
- { path: src/battle_partner/goompa.o }
- name: battle_partner_goombario
vram_class: battle_partner
keep_sections: False
files:
- { path: src/battle_partner/goombario.o }
- name: assets1
vram_class: segment_05
files:
- { path: src/assets/texture.o }
- { path: src/assets/dlist.o }
```
The above example defines two vram classes, `battle_partner` which defines
`keep_sections` to keep only the `.text` section of the files of the segments
that will reference thise vram class, and `segment_05` which will keep _every_
section of every segment referencing it.
The `battle_partner_goompa` segment references the `battle_partner` vram class
and neither the segment itself or the files within the segment specify their own
`keep_sections`, meaning all the `.text` sections of all the files of this
segment will be wrapped with `KEEP`s.
On the other hand, the `battle_partner_goombario` segment (which references the
`battle_partner` vram class too) sets its `keep_sections` attribute to `False`,
meaning that no file of this segment should be wrapped with `KEEP`s, overriding
the configuration of the `battle_partner` vram class for this specific segment.
Finally the `assets1` segment will emit `KEEP`s for all the sections of every
file on the segment since the `segment_05` vram class did set `True` to the
`keep_sections` attribute.
### Valid values
Either a boolean or a list of sections (list of strings).
### Default
`False`
3 changes: 3 additions & 0 deletions slinky/src/absent_nullable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,10 @@ impl<T> AbsentNullable<T> {
AbsentNullable::Value(v) => Ok(v),
}
}
}

impl<T> AbsentNullable<T> {
#[must_use]
pub fn has_value(&self) -> bool {
match self {
AbsentNullable::Absent | AbsentNullable::Null => false,
Expand Down
15 changes: 13 additions & 2 deletions slinky/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use crate::{
absent_nullable::AbsentNullable, assert_entry::AssertEntrySerial,
required_symbol::RequiredSymbolSerial, segment::SegmentSerial, settings::SettingsSerial,
symbol_assignment::SymbolAssignmentSerial, traits::Serial, vram_class::VramClassSerial,
AssertEntry, RequiredSymbol, Segment, Settings, SlinkyError, SymbolAssignment, VramClass,
AssertEntry, KeepSections, RequiredSymbol, Segment, Settings, SlinkyError, SymbolAssignment,
VramClass,
};

#[derive(PartialEq, Debug)]
Expand Down Expand Up @@ -89,7 +90,7 @@ impl DocumentSerial {
.get_non_null("vram_classes", Vec::new)?
.unserialize(&settings)?;

let segments = self.segments.unserialize(&settings)?;
let mut segments = self.segments.unserialize(&settings)?;

let entry = self.entry.get_non_null_no_default("entry")?;

Expand All @@ -108,6 +109,16 @@ impl DocumentSerial {
.get_non_null("asserts", Vec::new)?
.unserialize(&settings)?;

for segment in segments.iter_mut() {
if let Some(vram_class_name) = &segment.vram_class {
if let Some(vram_class) = vram_classes.iter().find(|x| x.name == *vram_class_name) {
if vram_class.keep_sections != KeepSections::Absent {
segment.pass_down_keep_sections(&vram_class.keep_sections);
}
}
}
}

Ok(Document {
settings,
vram_classes,
Expand Down
Loading

0 comments on commit 0fc03a2

Please sign in to comment.