From 582ce2dba2754f3be4a8cf5782bab3c3c0879896 Mon Sep 17 00:00:00 2001 From: Vishruth Thimmaiah Date: Mon, 6 Jul 2026 04:49:19 +0530 Subject: [PATCH 1/2] feat: support the DEFINED command in linker scripts Signed-off-by: Vishruth Thimmaiah --- LINKER_SCRIPT_SUPPORT.md | 4 ++-- libwild/src/expression_eval.rs | 3 +++ libwild/src/linker_script.rs | 11 +++++++++-- .../linker-script-assert-pass.c | 2 ++ .../linker-script-assert-pass.ld | 9 ++++++++- 5 files changed, 24 insertions(+), 5 deletions(-) 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..41fc15cb0 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 @@ -2,3 +2,5 @@ //#RunEnabled:false //#DiffEnabled:false void _start() {} + +int symbol4 = 0x4000; 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..e5224bceb 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,7 @@ 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 is not defined"); From ad2d8675b037785303f3e6eea49ee5b8c59951ce Mon Sep 17 00:00:00 2001 From: Vishruth Thimmaiah Date: Wed, 8 Jul 2026 11:17:07 +0530 Subject: [PATCH 2/2] tests: check for weak symbols Signed-off-by: Vishruth Thimmaiah --- .../linker-script-assert-pass/linker-script-assert-pass.c | 4 ++++ .../linker-script-assert-pass/linker-script-assert-pass.ld | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) 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 41fc15cb0..727e5f906 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 @@ -4,3 +4,7 @@ void _start() {} int symbol4 = 0x4000; +int symbol6 __attribute__((weak)); +int symbol7 __attribute__((weak)) = 0x7000; +extern int symbol8 __attribute__((weak)); +extern int symbol9; 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 e5224bceb..4c67fbb94 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 @@ -33,4 +33,8 @@ ASSERT((symbol1 > symbol2 ? symbol1 : symbol2) == MAX(symbol1, symbol2), "Expect 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 is not 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"); +ASSERT(!DEFINED(symbol9), "symbol9 should not be defined");