Skip to content

Commit

Permalink
Output symbol header
Browse files Browse the repository at this point in the history
Fixes #13
  • Loading branch information
AngheloAlf committed Mar 12, 2024
1 parent 2e4e532 commit c9fb5e1
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 4 deletions.
89 changes: 89 additions & 0 deletions docs/file_format/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ settings:
target_path: build/game.elf
```

### Valid values

Non-empty path.

## `target_path`

The path to the file that will result of linking, usually an `.elf` file.
Expand All @@ -139,6 +143,91 @@ settings:
target_path: build/game.elf
```

### Valid values

Non-empty path.

## `symbols_header_path`

Path to output a C header containing the generated linker symbols.

The symbols are declared as `extern` and their type can be customized with
[`symbols_header_type`](#symbols_header_type) and
[`symbols_header_as_array`](#symbols_header_as_array).

This file is generated only if `symbols_header_path` is specified.

### Example

```yaml
settings:
symbols_header_path: include/linker_symbols.h
```

### Valid values

Non-empty path.

## `symbols_header_type`

The type used for every linker symbol on the generated header.

This option is ignored if [`symbols_header_path`](#symbols_header_path) was not
set.

### Example

```yaml
settings:
symbols_header_path: include/linker_symbols.h
symbols_header_type: u32
```

Generates entries like:

```c
extern u32 main_BSS_START[];
```

### Valid values

String

### Default value

`char`

## `symbols_header_as_array`

Allows customizing if the entries from the generated symbols header should be
declared as arrays or not.

This option is ignored if [`symbols_header_path`](#symbols_header_path) was not
set.

### Example

```yaml
settings:
symbols_header_path: include/linker_symbols.h
symbols_header_type: Addr
symbols_header_as_array: False
```

Generates entries like:

```c
extern Addr main_BSS_START;
```

### Valid values

Boolean

### Default value

`True`

## `sections_allowlist`

A list of sections to that should be preserved during linking.
Expand Down
4 changes: 4 additions & 0 deletions slinky-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,8 @@ fn main() {
.expect("Error writing dependencies file");
}
}

if let Some(symbols_header_path) = &document.settings.symbols_header_path {
writer.save_symbol_header(symbols_header_path).expect("Error writing symbol header file");
}
}
60 changes: 58 additions & 2 deletions slinky/src/linker_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ impl<'a> LinkerWriter<'a> {
assert!(self.indent_level == 0);
}

// TODO: figure out a better way to handle Options
pub fn add_segment(&mut self, segment: &Segment) {
let style = &self.settings.linker_symbols_style;
let dotted_seg_name = format!(".{}", segment.name);
Expand Down Expand Up @@ -174,6 +173,63 @@ impl<'a> LinkerWriter<'a> {

ret
}

pub fn save_symbol_header(&self, path: &Path) -> Result<(), SlinkyError> {
let mut f = utils::create_file_and_parents(path)?;

if let Err(e) = write!(f, "#ifndef HEADER_SYMBOLS_H\n#define HEADER_SYMBOLS_H\n\n") {
return Err(SlinkyError::FailedFileWrite {
path: path.to_path_buf(),
description: e.to_string(),
contents: "".into(),
});
}

let arr_suffix = if self.settings.symbols_header_as_array { "[]" } else {""};

let mut linker_symbols_sorted: Vec<_> = (&self.linker_symbols).into_iter().collect();
linker_symbols_sorted.sort();

for sym in linker_symbols_sorted {
if let Err(e) = writeln!(f, "extern {} {}{};", self.settings.symbols_header_type, sym, arr_suffix) {
return Err(SlinkyError::FailedFileWrite {
path: path.to_path_buf(),
description: e.to_string(),
contents: sym.into(),
});
}
}

if let Err(e) = write!(f, "\n#endif\n") {
return Err(SlinkyError::FailedFileWrite {
path: path.to_path_buf(),
description: e.to_string(),
contents: "".into(),
});
}

Ok(())
}

#[must_use]
pub fn export_symbol_header_as_string(&self) -> String {
let mut ret = String::new();

ret += "#ifndef HEADER_SYMBOLS_H\n#define HEADER_SYMBOLS_H\n\n";

let arr_suffix = if self.settings.symbols_header_as_array { "[]" } else {""};

let mut linker_symbols_sorted: Vec<_> = (&self.linker_symbols).into_iter().collect();
linker_symbols_sorted.sort();

for sym in linker_symbols_sorted {
ret += &format!("extern {} {}{};", self.settings.symbols_header_type, sym, arr_suffix);
}

ret += "\n#endif\n";

ret
}
}

// internal functions
Expand Down Expand Up @@ -209,7 +265,7 @@ impl LinkerWriter<'_> {

self.writeln(&format!("{} = {};", symbol, value));

self.linker_symbols.insert(value.to_string());
self.linker_symbols.insert(symbol.to_string());
}

fn align_symbol(&mut self, symbol: &str, align_value: u32) {
Expand Down
41 changes: 39 additions & 2 deletions slinky/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub struct Settings {
pub d_path: Option<PathBuf>,
pub target_path: Option<PathBuf>,

pub symbols_header_path: Option<PathBuf>,
pub symbols_header_type: String,
pub symbols_header_as_array: bool,

pub sections_allowlist: Vec<String>,
pub sections_allowlist_extra: Vec<String>,
pub sections_denylist: Vec<String>,
Expand Down Expand Up @@ -54,6 +58,18 @@ fn settings_default_target_path() -> Option<PathBuf> {
None
}

fn settings_default_symbols_header_path() -> Option<PathBuf> {
None
}

fn settings_default_symbols_header_type() -> String {
"char".to_string()
}

fn settings_default_symbols_header_as_array() -> bool {
true
}

fn settings_default_hardcoded_gp_value() -> Option<u32> {
None
}
Expand Down Expand Up @@ -125,10 +141,14 @@ impl Default for Settings {
base_path: settings_default_base_path(),
linker_symbols_style: settings_default_linker_symbols_style(),

hardcoded_gp_value: settings_default_hardcoded_gp_value(),

d_path: settings_default_d_path(),
target_path: settings_default_target_path(),

hardcoded_gp_value: settings_default_hardcoded_gp_value(),
symbols_header_path: settings_default_symbols_header_path(),
symbols_header_type: settings_default_symbols_header_type(),
symbols_header_as_array: settings_default_symbols_header_as_array(),

sections_allowlist: settings_default_sections_allowlist(),
sections_allowlist_extra: settings_default_sections_allowlist_extra(),
Expand Down Expand Up @@ -157,13 +177,20 @@ pub(crate) struct SettingsSerial {
#[serde(default)]
pub linker_symbols_style: AbsentNullable<LinkerSymbolsStyle>,

#[serde(default)]
pub hardcoded_gp_value: AbsentNullable<u32>,

#[serde(default)]
pub d_path: AbsentNullable<PathBuf>,
#[serde(default)]
pub target_path: AbsentNullable<PathBuf>,

#[serde(default)]
pub hardcoded_gp_value: AbsentNullable<u32>,
pub symbols_header_path: AbsentNullable<PathBuf>,
#[serde(default)]
pub symbols_header_type: AbsentNullable<String>,
#[serde(default)]
pub symbols_header_as_array: AbsentNullable<bool>,

#[serde(default)]
pub sections_allowlist: AbsentNullable<Vec<String>>,
Expand Down Expand Up @@ -215,6 +242,10 @@ impl SettingsSerial {
.target_path
.get_optional_nullable("target_path", settings_default_target_path)?;

let symbols_header_path = self.symbols_header_path.get_optional_nullable("symbols_header_path", settings_default_symbols_header_path)?;
let symbols_header_type = self.symbols_header_type.get_non_null("symbols_header_type", settings_default_symbols_header_type)?;
let symbols_header_as_array = self.symbols_header_as_array.get_non_null("symbols_header_as_array", settings_default_symbols_header_as_array)?;

let sections_allowlist = self
.sections_allowlist
.get_non_null("sections_allowlist", settings_default_sections_allowlist)?;
Expand Down Expand Up @@ -268,8 +299,14 @@ impl SettingsSerial {
base_path,
linker_symbols_style,
hardcoded_gp_value,

d_path,
target_path,

symbols_header_path,
symbols_header_type,
symbols_header_as_array,

sections_allowlist,
sections_allowlist_extra,
sections_denylist,
Expand Down
4 changes: 4 additions & 0 deletions tests/input_files/hardcoded_gp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ settings:

subalign: null

symbols_header_path: tests/linker_scripts/hardcoded_gp.h
symbols_header_as_array: False
symbols_header_type: Addr

segments:
- name: main
fixed_vram: 0x80010200
Expand Down
2 changes: 2 additions & 0 deletions tests/input_files/makerom_zelda_like.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ settings:
subalign: null
linker_symbols_style: makerom

symbols_header_path: tests/linker_scripts/makerom_zelda_like.h

segments:
- name: makerom
fixed_vram: 0x80024C00
Expand Down
35 changes: 35 additions & 0 deletions tests/linker_scripts/hardcoded_gp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef HEADER_SYMBOLS_H
#define HEADER_SYMBOLS_H

extern Addr main_BSS_END;
extern Addr main_BSS_SIZE;
extern Addr main_BSS_START;
extern Addr main_DATA_END;
extern Addr main_DATA_SIZE;
extern Addr main_DATA_START;
extern Addr main_RODATA_END;
extern Addr main_RODATA_SIZE;
extern Addr main_RODATA_START;
extern Addr main_ROM_END;
extern Addr main_ROM_SIZE;
extern Addr main_ROM_START;
extern Addr main_SBSS_END;
extern Addr main_SBSS_SIZE;
extern Addr main_SBSS_START;
extern Addr main_SDATA_END;
extern Addr main_SDATA_SIZE;
extern Addr main_SDATA_START;
extern Addr main_TEXT_END;
extern Addr main_TEXT_SIZE;
extern Addr main_TEXT_START;
extern Addr main_VRAM;
extern Addr main_VRAM_END;
extern Addr main_VRAM_SIZE;
extern Addr main_alloc_VRAM;
extern Addr main_alloc_VRAM_END;
extern Addr main_alloc_VRAM_SIZE;
extern Addr main_noload_VRAM;
extern Addr main_noload_VRAM_END;
extern Addr main_noload_VRAM_SIZE;

#endif
Loading

0 comments on commit c9fb5e1

Please sign in to comment.