Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: + supported in ORIGIN #70

Merged
merged 11 commits into from
Apr 4, 2022
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ env_logger = { version = "0.9", default-features = false }
log = "0.4"
object = { version = "0.26", default-features = false, features = ["read_core", "elf", "std"] }
getrandom = "0.2"

regex = "1.5"
Dajamante marked this conversation as resolved.
Show resolved Hide resolved
[dev-dependencies]
assert_cmd = "2.0"
rstest = "0.11"
Expand Down
160 changes: 125 additions & 35 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,17 @@ macro_rules! eat {
};
}

/// This macro search `token` in a line and returns it, or , else `continue` loop iteration.
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
macro_rules! tryc {
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
($expr:expr) => {
if let Ok(x) = $expr {
x
} else {
continue;
}
};
}

fn get_includes_from_linker_script(linker_script: &str) -> Vec<&str> {
let mut includes = vec![];
for mut line in linker_script.lines() {
Expand All @@ -284,16 +295,6 @@ fn get_includes_from_linker_script(linker_script: &str) -> Vec<&str> {
/// Looks for "RAM : ORIGIN = $origin, LENGTH = $length"
// FIXME this is a dumb line-by-line parser
fn find_ram_in_linker_script(linker_script: &str) -> Option<MemoryEntry> {
macro_rules! tryc {
($expr:expr) => {
if let Ok(x) = $expr {
x
} else {
continue;
}
};
}

for (index, mut line) in linker_script.lines().enumerate() {
line = line.trim();
line = eat!(line, "RAM");
Expand All @@ -306,38 +307,18 @@ fn find_ram_in_linker_script(linker_script: &str) -> Option<MemoryEntry> {
line = eat!(line, ":");
line = eat!(line, "ORIGIN");
line = eat!(line, "=");
let boundary_pos = tryc!(line.find(|c| c == ',').ok_or(()));

let origin = perform_addition(&line[..boundary_pos]);

let boundary_pos = tryc!(line.find(|c| c == ',' || c == ' ').ok_or(()));
const HEX: &str = "0x";
let origin = if line.starts_with(HEX) {
tryc!(u64::from_str_radix(&line[HEX.len()..boundary_pos], 16))
} else {
tryc!(line[..boundary_pos].parse())
};
line = line[boundary_pos..].trim();

line = eat!(line, ",");
line = eat!(line, "LENGTH");
line = eat!(line, "=");

let segments: Vec<&str> = line.split('+').map(|s| s.trim().trim_end()).collect();
let mut total_length = 0;
for segment in segments {
let boundary_pos = segment
.find(|c| c == 'K' || c == 'M')
.unwrap_or(segment.len());
let length: u64 = tryc!(segment[..boundary_pos].parse());
let raw = &segment[boundary_pos..];
let mut chars = raw.chars();
let unit = chars.next();
if unit == Some('K') {
total_length += length * 1024;
} else if unit == Some('M') {
total_length += length * 1024 * 1024;
} else if unit == None {
total_length += length;
}
}
let total_length = perform_addition(line);

return Some(MemoryEntry {
line: index,
origin,
Expand All @@ -348,6 +329,37 @@ fn find_ram_in_linker_script(linker_script: &str) -> Option<MemoryEntry> {
None
}

/// Perform addition when ORIGN or LENGTH variables contain an addition
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
fn perform_addition(line: &str) -> u64 {
let segments: Vec<&str> = line.split('+').map(|s| s.trim().trim_end()).collect();
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved

let mut total_length = 0;
for segment in segments {
let boundary_pos = segment
.find(|c| c == 'K' || c == 'M')
.unwrap_or(segment.len());
const HEX: &str = "0x";
// Special case parsing for hex numbers.
let length: u64 = if segment.starts_with(HEX) {
tryc!(u64::from_str_radix(&segment[HEX.len()..boundary_pos], 16))
} else {
tryc!(segment[..boundary_pos].parse())
};
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved

let raw = &segment[boundary_pos..];
let mut chars = raw.chars();
let unit = chars.next();
if unit == Some('K') {
total_length += length * 1024;
} else if unit == Some('M') {
total_length += length * 1024 * 1024;
} else if unit == None {
total_length += length;
}
}
total_length
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -430,6 +442,84 @@ INCLUDE device.x
);
}

#[test]
fn parse_plus_origin_k() {
Urhengulas marked this conversation as resolved.
Show resolved Hide resolved
const LINKER_SCRIPT: &str = "MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 2M
RAM : ORIGIN = 0x20020000 + 100K, LENGTH = 368K
}

INCLUDE device.x
";

assert_eq!(
find_ram_in_linker_script(LINKER_SCRIPT),
Some(MemoryEntry {
line: 3,
origin: 0x20020000 + (100 * 1024),
length: 368 * 1024,
})
);

assert_eq!(
get_includes_from_linker_script(LINKER_SCRIPT),
vec!["device.x"]
);
}

#[test]
fn parse_plus_origin_no_units() {
const LINKER_SCRIPT: &str = "MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 2M
RAM : ORIGIN = 0x20020000 + 1000, LENGTH = 368K
}

INCLUDE device.x
";

assert_eq!(
find_ram_in_linker_script(LINKER_SCRIPT),
Some(MemoryEntry {
line: 3,
origin: 0x20020000 + 1000,
length: 368 * 1024,
})
);

assert_eq!(
get_includes_from_linker_script(LINKER_SCRIPT),
vec!["device.x"]
);
}

#[test]
fn parse_plus_origin_m() {
const LINKER_SCRIPT: &str = "MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 2M
RAM : ORIGIN = 0x20020000 + 100M, LENGTH = 368K
}

INCLUDE device.x
";

assert_eq!(
find_ram_in_linker_script(LINKER_SCRIPT),
Some(MemoryEntry {
line: 3,
origin: 0x20020000 + (100 * 1024 * 1024),
length: 368 * 1024,
})
);

assert_eq!(
get_includes_from_linker_script(LINKER_SCRIPT),
vec!["device.x"]
);
}

// test attributes https://sourceware.org/binutils/docs/ld/MEMORY.html
#[test]
fn parse_attributes() {
Expand Down