diff --git a/LINKER_SCRIPT_SUPPORT.md b/LINKER_SCRIPT_SUPPORT.md index 635b63f81..fe68fe18e 100644 --- a/LINKER_SCRIPT_SUPPORT.md +++ b/LINKER_SCRIPT_SUPPORT.md @@ -82,7 +82,7 @@ end lists the features required to link the Linux kernel. | `MIN(a, b)` | โœ… | | | `MAX(a, b)` | โœ… | | | Ternary operator (`condition ? a : b`) | โœ… | | -| `DEFINED(sym)` | ๐Ÿ“… | | +| `DEFINED(sym)` | โœ… | | | `SIZEOF_HEADERS` | โœ… | | | `SEGMENT_START(segment, default)` | โœ… | Supports `"text"`, `"data"`, `"bss"`, `"rodata"`; returns `-Ttext`/`-Tdata`/`-Tbss` override if provided, otherwise `default`; unknown segment names always return `default` | @@ -122,6 +122,6 @@ see at a glance what remains before Wild can link the kernel. | `CONSTRUCTORS` command | ๐Ÿ“… | | | `PHDRS` command for explicit program header definition | ๐Ÿงช | The FILEHDR and PHDRS keywords aren't yet supported. | | Ternary operator (`condition ? a : b`) | โœ… | | -| `DEFINED(sym)` function | ๐Ÿ“… | | +| `DEFINED(sym)` function | โœ… | | | `SIZEOF_HEADERS` built-in symbol | โœ… | | | `/DISCARD/` command | โœ… | | diff --git a/libwild/src/expression_eval.rs b/libwild/src/expression_eval.rs index 55dc469db..a2543ea6b 100644 --- a/libwild/src/expression_eval.rs +++ b/libwild/src/expression_eval.rs @@ -213,6 +213,9 @@ pub(crate) fn evaluate_expression<'data, P: Platform>( eval!(if_false) } } + Expression::Defined(name) => Ok(symbol_db + .get_unversioned(&UnversionedSymbolName::prehashed(name)) + .map_or(0, |_| 1)), } } diff --git a/libwild/src/linker_script.rs b/libwild/src/linker_script.rs index 12fc6c5af..02f975c85 100644 --- a/libwild/src/linker_script.rs +++ b/libwild/src/linker_script.rs @@ -170,7 +170,8 @@ pub(crate) struct Phdr<'a> { /// - Bitwise: &, |, ^, ~, <<, >> /// - Logical: &&, || /// - Unary: -, !, ~ -/// - Functions: SIZEOF, ALIGNOF, LENGTH, ORIGIN, ADDR, LOADADDR, ALIGN, MIN, MAX, SEGMENT_START +/// - Functions: SIZEOF, ALIGNOF, LENGTH, ORIGIN, ADDR, LOADADDR, ALIGN, MIN, MAX, SEGMENT_START, +/// DEFINED /// - Numbers (hex/decimal), symbols, location counter (.) /// - Parentheses for grouping /// - Ternary operator (? :) @@ -229,6 +230,7 @@ pub(crate) enum Expression<'a> { Box>, Box>, ), + Defined(&'a [u8]), } #[derive(Debug, PartialEq, Eq, Clone)] @@ -261,7 +263,8 @@ impl<'a> Expression<'a> { | Expression::Addr(_) | Expression::Loadaddr(_) | Expression::Symbol(_) - | Expression::SizeofHeaders => {} + | Expression::SizeofHeaders + | Expression::Defined(_) => {} Expression::Add(l, r) | Expression::Subtract(l, r) | Expression::Multiply(l, r) @@ -926,6 +929,10 @@ fn parse_identifier_or_function<'a>(input: &mut &'a BStr) -> winnow::Result { + let symbol = parse_function_arg.parse_next(input)?; + Ok(Expression::Defined(symbol)) + } _ => Err(ContextError::default()), } } else if ident == b"SIZEOF_HEADERS" { diff --git a/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.c b/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.c index 2d7222813..ed02a1f52 100644 --- a/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.c +++ b/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.c @@ -1,4 +1,15 @@ //#LinkArgs:-T ./linker-script-assert-pass.ld //#RunEnabled:false //#DiffEnabled:false -void _start() {} +//#Object:runtime.c +// RISC-V: BFD complains about missing __global_pointer$ (defined in the default linker script) +//#SkipArch:riscv64 + +#include "../common/runtime.h" + +int symbol4 = 0x4000; +int symbol6 __attribute__((weak)); +int symbol7 __attribute__((weak)) = 0x7000; +extern int symbol8 __attribute__((weak)); + +void _start() { exit_syscall(symbol4 + symbol6 + symbol7 + symbol8); } diff --git a/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.ld b/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.ld index a07aa74bf..32c487f5d 100644 --- a/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.ld +++ b/wild/tests/sources/elf/linker-script-assert-pass/linker-script-assert-pass.ld @@ -1,7 +1,10 @@ ENTRY(_start) SECTIONS { - .text : { *(.text*) } + .text : { + *(.text*) + symbol3 = 0x3000; + } .data : { *(.data*) } .bss : { *(.bss*) } } @@ -27,3 +30,10 @@ ASSERT(symbol1 + symbol2 != symbol1 - symbol2, "symbol1 + symbol2 must not be sy ASSERT(0xffffffff81000000 == (0xffffffff80000000 + (((symbol1 * 0x1000) + (symbol2 * 0x100 - 1)) & ~(0x200000 - 1))), "Incorrect Value"); ASSERT((5 > 4 ? !1 ? 3 : 5 : 4) == 5, "5 > 4 ? !1 ? 3 : 5 : 4 must be 5"); ASSERT((symbol1 > symbol2 ? symbol1 : symbol2) == MAX(symbol1, symbol2), "Expected MAX(symbol1, symbol2)"); +ASSERT(DEFINED(symbol1), "symbol1 must be defined"); +ASSERT(DEFINED(symbol3), "symbol3 must be defined"); +ASSERT(DEFINED(symbol4), "symbol4 must be defined"); +ASSERT(!DEFINED(symbol5), "symbol5 should not be defined"); +ASSERT(DEFINED(symbol6), "symbol6 must be defined"); +ASSERT(DEFINED(symbol7), "symbol7 must be defined"); +ASSERT(!DEFINED(symbol8), "symbol8 should not be defined");