Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 68 additions & 3 deletions libwild/src/expression_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::error::Warning;
use crate::grouping::Group;
use crate::layout::OutputRecordLayout;
use crate::linker_script::Expression;
use crate::linker_script::MemoryRegion;
use crate::output_section_id::OutputSections;
use crate::output_section_id::SectionName;
use crate::output_section_map::OutputSectionMap;
Expand Down Expand Up @@ -44,6 +45,7 @@ pub(crate) fn evaluate_assertions<'data, P: Platform>(
section_layouts,
output_sections,
warning_callback,
&parsed.memory_regions,
)
.with_context(|| format!("{}:{}: Failed to evaluate ASSERT", parsed.input, line))?;

Expand All @@ -62,10 +64,17 @@ fn evaluate_expression<'data, P: Platform>(
section_layouts: &OutputSectionMap<OutputRecordLayout>,
output_sections: &OutputSections<'data, P>,
warning_callback: &WarningCallback,
memory_regions: &[MemoryRegion<'data>],
) -> Result<u64> {
macro_rules! eval {
($e:expr) => {
evaluate_expression($e, section_layouts, output_sections, warning_callback)
evaluate_expression(
$e,
section_layouts,
output_sections,
warning_callback,
memory_regions,
)
};
}

Expand Down Expand Up @@ -139,7 +148,31 @@ fn evaluate_expression<'data, P: Platform>(
Expression::LogicalNot(e) => Ok(u64::from(eval!(e)? == 0)),
Expression::BitwiseNot(e) => Ok(!eval!(e)?),
Expression::Negate(e) => Ok(eval!(e)?.wrapping_neg()),
Expression::Origin(_) | Expression::Length(_) => todo!(),

Expression::Origin(name) => {
let region = memory_regions
.iter()
.find(|r| r.name == *name)
.ok_or_else(|| {
crate::error!(
"ORIGIN: memory region '{}' not found",
String::from_utf8_lossy(name)
)
})?;
eval!(&region.origin)
}
Expression::Length(name) => {
let region = memory_regions
.iter()
.find(|r| r.name == *name)
.ok_or_else(|| {
crate::error!(
"LENGTH: memory region '{}' not found",
String::from_utf8_lossy(name)
)
})?;
eval!(&region.length)
}
}
}

Expand Down Expand Up @@ -208,7 +241,7 @@ mod tests {

fn eval_const(expr: &Expression<'static>) -> Result<u64> {
let (layouts, sections) = dummy_context();
evaluate_expression::<Elf>(expr, &layouts, &sections, &|_| {})
evaluate_expression::<Elf>(expr, &layouts, &sections, &|_| {}, &[])
}

#[test]
Expand Down Expand Up @@ -527,6 +560,7 @@ mod tests {
symbol_defs: Vec::new(),
assertions,
file_bytes: b"",
memory_regions: Vec::new(),
},
symbol_id_range: SymbolIdRange::empty(),
file_id: FileId::new(0, 0),
Expand Down Expand Up @@ -559,4 +593,35 @@ mod tests {
let err = evaluate_assertions::<Elf>(&[group], &layouts, &sections, &|_| {}).unwrap_err();
assert!(err.to_string().contains("intentional failure"));
}

#[test]
fn test_memory_functions_evaluation() {
let (layouts, sections) = dummy_context();
let regions = [
MemoryRegion {
name: b"rom",
origin: Expression::Number(0x08000000),
length: Expression::Number(0x100000),
},
MemoryRegion {
name: b"ram",
origin: Expression::Number(0x20000000),
length: Expression::Number(0x40000),
},
];
let eval = |expr: &Expression| {
evaluate_expression::<Elf>(expr, &layouts, &sections, &|_| {}, &regions)
};
assert_eq!(eval(&Expression::Origin(b"rom")).unwrap(), 0x08000000);
assert_eq!(eval(&Expression::Length(b"rom")).unwrap(), 0x100000);
assert_eq!(eval(&Expression::Origin(b"ram")).unwrap(), 0x20000000);
assert_eq!(eval(&Expression::Length(b"ram")).unwrap(), 0x40000);
// end of rom = origin + length
let end = Expression::Add(
Box::new(Expression::Origin(b"rom")),
Box::new(Expression::Length(b"rom")),
);
assert_eq!(eval(&end).unwrap(), 0x08100000);
assert!(eval(&Expression::Origin(b"flash")).is_err());
}
}
4 changes: 4 additions & 0 deletions libwild/src/layout_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ impl<'data> LayoutRulesBuilder<'data> {
) -> Result<ProcessedLinkerScript<'data>> {
let mut symbol_defs = Vec::new();
let mut assertions = Vec::new();
let mut memory_regions = Vec::new();

for cmd in &input.script.commands {
if let linker_script::Command::Provide(provide) = cmd {
Expand Down Expand Up @@ -245,6 +246,8 @@ impl<'data> LayoutRulesBuilder<'data> {
}
} else if let linker_script::Command::Assert(assert_cmd) = cmd {
assertions.push(assert_cmd.clone());
} else if let linker_script::Command::Memory(regions) = cmd {
memory_regions = regions.clone();
}
}

Expand All @@ -256,6 +259,7 @@ impl<'data> LayoutRulesBuilder<'data> {
entry: None,
},
file_bytes: input.script_bytes,
memory_regions,
})
}

Expand Down
2 changes: 1 addition & 1 deletion libwild/src/linker_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub(crate) struct Section<'a> {
pub(crate) alignment: Option<Alignment>,
}

#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) struct MemoryRegion<'a> {
pub(crate) name: &'a [u8],
pub(crate) origin: Expression<'a>,
Expand Down
1 change: 1 addition & 0 deletions libwild/src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub(crate) struct ProcessedLinkerScript<'data> {
/// Raw bytes of the linker script file. Used to compute line numbers from
/// `AssertCommand::remainder` when reporting errors.
pub(crate) file_bytes: &'data [u8],
pub(crate) memory_regions: Vec<crate::linker_script::MemoryRegion<'data>>,
}

#[derive(Debug)]
Expand Down
Loading