* [RFC PATCH 1/9] sandbox: Drop special link order treatment of start.o and sdl.o
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-25 14:30 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute Rasmus Villemoes
` (7 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
From: Tom Rini <trini@konsulko.com>
On hardware architectures, we need to treat start.o (generated from
start.S) very special due to the constraints of being a program running
on hardware in an unknown state. These objects are treated a little
different than the rest by the linker and linker scripts on various
architectures.
Sandbox is different, and doesn't need to do that. In fact, it can lead
to hard to diagnose problems because of just how subtly different the
treatment is. For example, the comment about LTO in include/event.h
introduced with commit 87a5d1b5d012 ("event: Add basic support for
events") was only a sandbox issue because of the event in start.c and
in turn linking start.o isn't treated the same way as an archive with
all its sections considered.
Correct all of this by removing the "head-" lines for cpu.o and sdl.o
from arch/sandbox/Makefile (and unused cmd_cc_sdl.o lines) and change
arch/sandbox/cpu/Makefile to treating them both with "obj-" and not
"extra-".
Signed-off-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
arch/sandbox/Makefile | 9 ---------
arch/sandbox/cpu/Makefile | 5 ++---
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile
index 5bbf9f1f96b..0360d2bd886 100644
--- a/arch/sandbox/Makefile
+++ b/arch/sandbox/Makefile
@@ -1,13 +1,4 @@
# SPDX-License-Identifier: GPL-2.0+
-head-y := arch/sandbox/cpu/start.o
-head-$(CONFIG_SANDBOX_SDL) += arch/sandbox/cpu/sdl.o
libs-y += arch/sandbox/cpu/
libs-y += arch/sandbox/lib/
-
-# sdl.c fails to compile with -fshort-wchar using musl.
-cmd_cc_sdl.o = $(CC) $(filter-out -nostdinc -fshort-wchar, \
- $(patsubst -I%,-idirafter%,$(c_flags))) -fno-lto -c -o $@ $<
-
-$(obj)/sdl.o: $(src)/sdl.c FORCE
- $(call if_changed_dep,cc_sdl.o)
diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile
index ee3c04c49e1..eb6bf6302e2 100644
--- a/arch/sandbox/cpu/Makefile
+++ b/arch/sandbox/cpu/Makefile
@@ -5,9 +5,8 @@
# (C) Copyright 2000-2003
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-y := cache.o cpu.o state.o initjmp.o os.o
-extra-y := start.o
-extra-$(CONFIG_SANDBOX_SDL) += sdl.o
+obj-y := start.o cache.o cpu.o state.o initjmp.o os.o
+obj-$(CONFIG_SANDBOX_SDL) += sdl.o
obj-$(CONFIG_XPL_BUILD) += spl.o
obj-$(CONFIG_ETH_SANDBOX_RAW) += eth-raw-os.o
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 1/9] sandbox: Drop special link order treatment of start.o and sdl.o
2026-05-22 21:27 ` [RFC PATCH 1/9] sandbox: Drop special link order treatment of start.o and sdl.o Rasmus Villemoes
@ 2026-05-25 14:30 ` Simon Glass
0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-25 14:30 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Tom,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> sandbox: Drop special link order treatment of start.o and sdl.o
>
> On hardware architectures, we need to treat start.o (generated from
> start.S) very special due to the constraints of being a program running
> on hardware in an unknown state. These objects are treated a little
> different than the rest by the linker and linker scripts on various
> architectures.
>
> Sandbox is different, and doesn't need to do that. In fact, it can lead
> to hard to diagnose problems because of just how subtly different the
> treatment is. For example, the comment about LTO in include/event.h
> introduced with commit 87a5d1b5d012 ("event: Add basic support for
> events") was only a sandbox issue because of the event in start.c and
> in turn linking start.o isn't treated the same way as an archive with
> all its sections considered.
>
> Correct all of this by removing the 'head-' lines for cpu.o and sdl.o
> from arch/sandbox/Makefile (and unused cmd_cc_sdl.o lines) and change
> arch/sandbox/cpu/Makefile to treating them both with 'obj-' and not
to treat them both
> 'extra-'.
> [...]
>
> arch/sandbox/Makefile | 9 ---------
> arch/sandbox/cpu/Makefile | 5 ++---
> 2 files changed, 2 insertions(+), 12 deletions(-)
> diff --git a/arch/sandbox/cpu/Makefile b/arch/sandbox/cpu/Makefile
> @@ -5,9 +5,8 @@
> # (C) Copyright 2000-2003
> # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
>
> -obj-y := cache.o cpu.o state.o initjmp.o os.o
> -extra-y := start.o
> -extra-$(CONFIG_SANDBOX_SDL) += sdl.o
> +obj-y := start.o cache.o cpu.o state.o initjmp.o os.o
> +obj-$(CONFIG_SANDBOX_SDL) += sdl.o
The sandbox-specific cmd_cc_sdl.o override already covers sdl.o once
it moves into obj-y, so dropping the duplicate block from
arch/sandbox/Makefile looks safe
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
2026-05-22 21:27 ` [RFC PATCH 1/9] sandbox: Drop special link order treatment of start.o and sdl.o Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-25 15:02 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 3/9] event: Remove obsolete comment and __used attributes Rasmus Villemoes
` (6 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
From: Tom Rini <trini@konsulko.com>
Whenever we declare something to be in a linker list, we want it to be
included. This is why all of our linker scripts have a line similar to:
KEEP(*(SORT(__u_boot_list*)));
to ensure that any linker list found in any of the archives we are
linking together makes it to the final object. Remove the places where
we set an attribute saying that it is unused, or maybe_unused.
Signed-off-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/linker_lists.h | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/include/linker_lists.h b/include/linker_lists.h
index 4425fcb6785..a8b7e2c9f2b 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -69,7 +69,6 @@
*/
#define ll_entry_declare(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
- __attribute__((unused)) \
__section("__u_boot_list_2_"#_list"_2_"#_name)
/**
@@ -92,7 +91,6 @@
*/
#define ll_entry_declare_list(_type, _name, _list) \
_type _u_boot_list_2_##_list##_2_##_name[] __aligned(4) \
- __attribute__((unused)) \
__section("__u_boot_list_2_"#_list"_2_"#_name)
/*
@@ -125,7 +123,6 @@
#define ll_entry_start(_type, _list) \
({ \
static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
- __attribute__((unused)) \
__section("__u_boot_list_2_"#_list"_1"); \
_type * tmp = (_type *)&start; \
asm("":"+r"(tmp)); \
@@ -167,7 +164,7 @@
*/
#define ll_entry_end(_type, _list) \
({ \
- static char end[0] __aligned(1) __attribute__((unused)) \
+ static char end[0] __aligned(1) \
__section("__u_boot_list_2_"#_list"_3"); \
_type * tmp = (_type *)&end; \
asm("":"+r"(tmp)); \
@@ -251,7 +248,7 @@
*/
#define ll_start_decl(_sym, _type, _list) \
static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
- __maybe_unused __section("__u_boot_list_2_" #_list "_1")
+ __section("__u_boot_list_2_" #_list "_1")
/*
* ll_end_decl uses __aligned(1) to avoid padding before the end marker.
@@ -259,7 +256,7 @@
*/
#define ll_end_decl(_sym, _type, _list) \
static _type _sym[0] __aligned(1) \
- __maybe_unused __section("__u_boot_list_2_" #_list "_3")
+ __section("__u_boot_list_2_" #_list "_3")
/**
* ll_entry_get() - Retrieve entry from linker-generated array by name
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute
2026-05-22 21:27 ` [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute Rasmus Villemoes
@ 2026-05-25 15:02 ` Simon Glass
2026-05-25 15:22 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:02 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> linker_lists: Do not set 'unused' attribute
>
> Whenever we declare something to be in a linker list, we want it to be
> included. This is why all of our linker scripts have a line similar to:
> KEEP(*(SORT(__u_boot_list*)));
> to ensure that any linker list found in any of the archives we are
> linking together makes it to the final object. Remove the places where
> we set an attribute saying that it is unused, or maybe_unused.
>
> Signed-off-by: Tom Rini <trini@konsulko.com>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
>
> include/linker_lists.h | 9 +++------
> 1 file changed, 3 insertions(+), 6 deletions(-)
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -69,7 +69,6 @@
> */
> #define ll_entry_declare(_type, _name, _list) \
> _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
> - __attribute__((unused)) \
> __section('__u_boot_list_2_'#_list'_2_'#_name)
The commit message conflates two unrelated things:
__attribute__((unused)) and __maybe_unused are purely warning
suppressions; they do not affect whether the symbol is emitted, kept
by the linker, or seen by LTO. The thing that prevents removal is
__used (and at the linker stage, KEEP()).
The real reason removal is safe is that none of these declarations
would have warned anyway - ll_entry_declare()/ll_entry_declare_list()
produce non-static externals (no -Wunused-variable for those),
ll_entry_start()/ll_entry_end() take the address of start[]/end[]
inside the same statement expression, and the symbols from
ll_start_decl()/ll_end_decl() are referenced by the caller (cmd_ut.c
is currently the only one). Please reword the commit message along
those lines; the KEEP() stuff belongs more naturally with patch 3.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute
2026-05-25 15:02 ` Simon Glass
@ 2026-05-25 15:22 ` Tom Rini
2026-05-25 15:33 ` Simon Glass
0 siblings, 1 reply; 32+ messages in thread
From: Tom Rini @ 2026-05-25 15:22 UTC (permalink / raw)
To: Simon Glass; +Cc: ravi, u-boot
[-- Attachment #1: Type: text/plain, Size: 2334 bytes --]
On Mon, May 25, 2026 at 09:02:02AM -0600, Simon Glass wrote:
> Hi,
>
> On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> > linker_lists: Do not set 'unused' attribute
> >
> > Whenever we declare something to be in a linker list, we want it to be
> > included. This is why all of our linker scripts have a line similar to:
> > KEEP(*(SORT(__u_boot_list*)));
> > to ensure that any linker list found in any of the archives we are
> > linking together makes it to the final object. Remove the places where
> > we set an attribute saying that it is unused, or maybe_unused.
> >
> > Signed-off-by: Tom Rini <trini@konsulko.com>
> > Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
> >
> > include/linker_lists.h | 9 +++------
> > 1 file changed, 3 insertions(+), 6 deletions(-)
>
> > diff --git a/include/linker_lists.h b/include/linker_lists.h
> > @@ -69,7 +69,6 @@
> > */
> > #define ll_entry_declare(_type, _name, _list) \
> > _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
> > - __attribute__((unused)) \
> > __section('__u_boot_list_2_'#_list'_2_'#_name)
>
> The commit message conflates two unrelated things:
> __attribute__((unused)) and __maybe_unused are purely warning
> suppressions; they do not affect whether the symbol is emitted, kept
> by the linker, or seen by LTO. The thing that prevents removal is
> __used (and at the linker stage, KEEP()).
>
> The real reason removal is safe is that none of these declarations
> would have warned anyway - ll_entry_declare()/ll_entry_declare_list()
> produce non-static externals (no -Wunused-variable for those),
> ll_entry_start()/ll_entry_end() take the address of start[]/end[]
> inside the same statement expression, and the symbols from
> ll_start_decl()/ll_end_decl() are referenced by the caller (cmd_ut.c
> is currently the only one). Please reword the commit message along
> those lines; the KEEP() stuff belongs more naturally with patch 3.
I don't think your analysis is correct. They are not unrelated things,
they're very much related and were really incorrect at introduction a
decade+ ago (and pre LTO) but I don't think it was worth adding a Fixes
tag.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute
2026-05-25 15:22 ` Tom Rini
@ 2026-05-25 15:33 ` Simon Glass
2026-05-25 15:46 ` Tom Rini
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:33 UTC (permalink / raw)
To: Tom Rini; +Cc: ravi, u-boot
Hi Tom,
On Mon, 25 May 2026 at 09:22, Tom Rini <trini@konsulko.com> wrote:
>
> On Mon, May 25, 2026 at 09:02:02AM -0600, Simon Glass wrote:
> > Hi,
> >
> > On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> > > linker_lists: Do not set 'unused' attribute
> > >
> > > Whenever we declare something to be in a linker list, we want it to be
> > > included. This is why all of our linker scripts have a line similar to:
> > > KEEP(*(SORT(__u_boot_list*)));
> > > to ensure that any linker list found in any of the archives we are
> > > linking together makes it to the final object. Remove the places where
> > > we set an attribute saying that it is unused, or maybe_unused.
> > >
> > > Signed-off-by: Tom Rini <trini@konsulko.com>
> > > Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
> > >
> > > include/linker_lists.h | 9 +++------
> > > 1 file changed, 3 insertions(+), 6 deletions(-)
> >
> > > diff --git a/include/linker_lists.h b/include/linker_lists.h
> > > @@ -69,7 +69,6 @@
> > > */
> > > #define ll_entry_declare(_type, _name, _list) \
> > > _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
> > > - __attribute__((unused)) \
> > > __section('__u_boot_list_2_'#_list'_2_'#_name)
> >
> > The commit message conflates two unrelated things:
> > __attribute__((unused)) and __maybe_unused are purely warning
> > suppressions; they do not affect whether the symbol is emitted, kept
> > by the linker, or seen by LTO. The thing that prevents removal is
> > __used (and at the linker stage, KEEP()).
> >
> > The real reason removal is safe is that none of these declarations
> > would have warned anyway - ll_entry_declare()/ll_entry_declare_list()
> > produce non-static externals (no -Wunused-variable for those),
> > ll_entry_start()/ll_entry_end() take the address of start[]/end[]
> > inside the same statement expression, and the symbols from
> > ll_start_decl()/ll_end_decl() are referenced by the caller (cmd_ut.c
> > is currently the only one). Please reword the commit message along
> > those lines; the KEEP() stuff belongs more naturally with patch 3.
>
> I don't think your analysis is correct. They are not unrelated things,
> they're very much related and were really incorrect at introduction a
> decade+ ago (and pre LTO) but I don't think it was worth adding a Fixes
> tag.
I mean that the compiler will warn if you declare a static symbol but
then don't use it in the same TU (hence the need for 'unused').
warning != inclusion/removal. I haven't quite figured out whether
those warnings have gone away, or something else has changed. It will
be easier to see when I can build this branch.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute
2026-05-25 15:33 ` Simon Glass
@ 2026-05-25 15:46 ` Tom Rini
0 siblings, 0 replies; 32+ messages in thread
From: Tom Rini @ 2026-05-25 15:46 UTC (permalink / raw)
To: Simon Glass; +Cc: ravi, u-boot
[-- Attachment #1: Type: text/plain, Size: 3123 bytes --]
On Mon, May 25, 2026 at 09:33:24AM -0600, Simon Glass wrote:
> Hi Tom,
>
> On Mon, 25 May 2026 at 09:22, Tom Rini <trini@konsulko.com> wrote:
> >
> > On Mon, May 25, 2026 at 09:02:02AM -0600, Simon Glass wrote:
> > > Hi,
> > >
> > > On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> > > > linker_lists: Do not set 'unused' attribute
> > > >
> > > > Whenever we declare something to be in a linker list, we want it to be
> > > > included. This is why all of our linker scripts have a line similar to:
> > > > KEEP(*(SORT(__u_boot_list*)));
> > > > to ensure that any linker list found in any of the archives we are
> > > > linking together makes it to the final object. Remove the places where
> > > > we set an attribute saying that it is unused, or maybe_unused.
> > > >
> > > > Signed-off-by: Tom Rini <trini@konsulko.com>
> > > > Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
> > > >
> > > > include/linker_lists.h | 9 +++------
> > > > 1 file changed, 3 insertions(+), 6 deletions(-)
> > >
> > > > diff --git a/include/linker_lists.h b/include/linker_lists.h
> > > > @@ -69,7 +69,6 @@
> > > > */
> > > > #define ll_entry_declare(_type, _name, _list) \
> > > > _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
> > > > - __attribute__((unused)) \
> > > > __section('__u_boot_list_2_'#_list'_2_'#_name)
> > >
> > > The commit message conflates two unrelated things:
> > > __attribute__((unused)) and __maybe_unused are purely warning
> > > suppressions; they do not affect whether the symbol is emitted, kept
> > > by the linker, or seen by LTO. The thing that prevents removal is
> > > __used (and at the linker stage, KEEP()).
> > >
> > > The real reason removal is safe is that none of these declarations
> > > would have warned anyway - ll_entry_declare()/ll_entry_declare_list()
> > > produce non-static externals (no -Wunused-variable for those),
> > > ll_entry_start()/ll_entry_end() take the address of start[]/end[]
> > > inside the same statement expression, and the symbols from
> > > ll_start_decl()/ll_end_decl() are referenced by the caller (cmd_ut.c
> > > is currently the only one). Please reword the commit message along
> > > those lines; the KEEP() stuff belongs more naturally with patch 3.
> >
> > I don't think your analysis is correct. They are not unrelated things,
> > they're very much related and were really incorrect at introduction a
> > decade+ ago (and pre LTO) but I don't think it was worth adding a Fixes
> > tag.
>
> I mean that the compiler will warn if you declare a static symbol but
> then don't use it in the same TU (hence the need for 'unused').
> warning != inclusion/removal. I haven't quite figured out whether
> those warnings have gone away, or something else has changed. It will
> be easier to see when I can build this branch.
It has always been incorrect to have these, and there's no real value in
having more commits removing incorrect code.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 3/9] event: Remove obsolete comment and __used attributes
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
2026-05-22 21:27 ` [RFC PATCH 1/9] sandbox: Drop special link order treatment of start.o and sdl.o Rasmus Villemoes
2026-05-22 21:27 ` [RFC PATCH 2/9] linker_lists: Do not set "unused" attribute Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-25 14:31 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros Rasmus Villemoes
` (5 subsequent siblings)
8 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
From: Tom Rini <trini@konsulko.com>
Now that we have both resolved the problem on sandbox that lead to a comment
about linker list entries being omitted as well as made linker lists
never list themselves as unused, we can update the event header file.
Remove the now obsolete comment and "__used" attribute marker.
Signed-off-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/event.h | 35 ++---------------------------------
1 file changed, 2 insertions(+), 33 deletions(-)
diff --git a/include/event.h b/include/event.h
index 3ce5f992b04..450281f666a 100644
--- a/include/event.h
+++ b/include/event.h
@@ -308,44 +308,13 @@ static inline const char *event_spy_id(struct evspy_info *spy)
#endif
}
-/*
- * It seems that LTO will drop list entries if it decides they are not used,
- * although the conditions that cause this are unclear.
- *
- * The example found is the following:
- *
- * static int sandbox_misc_init_f(void *ctx, struct event *event)
- * {
- * return sandbox_early_getopt_check();
- * }
- * EVENT_SPY_FULL(EVT_MISC_INIT_F, sandbox_misc_init_f);
- *
- * where EVENT_SPY_FULL uses ll_entry_declare()
- *
- * In this case, LTO decides to drop the sandbox_misc_init_f() function
- * (which is fine) but then drops the linker-list entry too. This means
- * that the code no longer works, in this case sandbox no-longer checks its
- * command-line arguments properly.
- *
- * Without LTO, the KEEP() command in the .lds file is enough to keep the
- * entry around. But with LTO it seems that the entry has already been
- * dropped before the link script is considered.
- *
- * The only solution I can think of is to mark linker-list entries as 'used'
- * using an attribute. This should be safe, since we don't actually want to drop
- * any of these. However this does slightly limit LTO's optimisation choices.
- *
- * Another issue has come up, only with clang: using 'static' makes it throw
- * away the linker-list entry sometimes, e.g. with the EVT_FT_FIXUP entry in
- * vbe_simple.c - so for now, make it global.
- */
#define EVENT_SPY_FULL(_type, _func) \
- __used ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
+ ll_entry_declare(struct evspy_info, _type ## _3_ ## _func, \
evspy_info) = _ESPY_REC(_type, _func)
/* Simple spy with no function arguments */
#define EVENT_SPY_SIMPLE(_type, _func) \
- __used ll_entry_declare(struct evspy_info_simple, \
+ ll_entry_declare(struct evspy_info_simple, \
_type ## _3_ ## _func, \
evspy_info) = _ESPY_REC_SIMPLE(_type, _func)
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 3/9] event: Remove obsolete comment and __used attributes
2026-05-22 21:27 ` [RFC PATCH 3/9] event: Remove obsolete comment and __used attributes Rasmus Villemoes
@ 2026-05-25 14:31 ` Simon Glass
0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-25 14:31 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> event: Remove obsolete comment and __used attributes
>
> Now that we have both resolved the problem on sandbox that lead to a comment
> about linker list entries being omitted as well as made linker lists
> never list themselves as unused, we can update the event header file.
> Remove the now obsolete comment and '__used' attribute marker.
>
> Signed-off-by: Tom Rini <trini@konsulko.com>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
>
> include/event.h | 35 ++---------------------------------
> 1 file changed, 2 insertions(+), 33 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (2 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 3/9] event: Remove obsolete comment and __used attributes Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-22 22:44 ` Tom Rini
2026-05-25 14:32 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix Rasmus Villemoes
` (4 subsequent siblings)
8 siblings, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
Instead of open-coding the same section and symbol naming scheme over
and over, add helper macros that take the list name (and, for entries,
the name of the entry/entries) and construct a suitable string
literal.
This will be particularly important when the followup patches add even
more uses of those names.
No functional change.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/linker_lists.h | 30 ++++++++++++++++++------------
1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/include/linker_lists.h b/include/linker_lists.h
index a8b7e2c9f2b..b6437ad6462 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -19,6 +19,12 @@
#if !defined(__ASSEMBLY__)
+#define ll_start_section_name(_list) "__u_boot_list_2_"#_list"_1"
+#define ll_entry_section_name(_list, _name) "__u_boot_list_2_"#_list"_2_"#_name
+#define ll_end_section_name(_list) "__u_boot_list_2_"#_list"_3"
+
+#define ll_entry_symbol_name(_list, _name) _u_boot_list_2_##_list##_2_##_name
+
/**
* llsym() - Access a linker-generated array entry
* @_type: Data type of the entry
@@ -27,7 +33,7 @@
* in a C variable name!
*/
#define llsym(_type, _name, _list) \
- ((_type *)&_u_boot_list_2_##_list##_2_##_name)
+ ((_type *)&ll_entry_symbol_name(_list, _name))
/**
* ll_entry_declare() - Declare linker-generated array entry
@@ -68,8 +74,8 @@
* };
*/
#define ll_entry_declare(_type, _name, _list) \
- _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
- __section("__u_boot_list_2_"#_list"_2_"#_name)
+ _type ll_entry_symbol_name(_list, _name) __aligned(4) \
+ __section(ll_entry_section_name(_list, _name))
/**
* ll_entry_declare_list() - Declare a list of link-generated array entries
@@ -90,8 +96,8 @@
* };
*/
#define ll_entry_declare_list(_type, _name, _list) \
- _type _u_boot_list_2_##_list##_2_##_name[] __aligned(4) \
- __section("__u_boot_list_2_"#_list"_2_"#_name)
+ _type ll_entry_symbol_name(_list, _name)[] __aligned(4) \
+ __section(ll_entry_section_name(_list, _name))
/*
* We need a 0-byte-size type for iterator symbols, and the compiler
@@ -123,7 +129,7 @@
#define ll_entry_start(_type, _list) \
({ \
static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
- __section("__u_boot_list_2_"#_list"_1"); \
+ __section(ll_start_section_name(_list)); \
_type * tmp = (_type *)&start; \
asm("":"+r"(tmp)); \
tmp; \
@@ -165,7 +171,7 @@
#define ll_entry_end(_type, _list) \
({ \
static char end[0] __aligned(1) \
- __section("__u_boot_list_2_"#_list"_3"); \
+ __section(ll_end_section_name(_list)); \
_type * tmp = (_type *)&end; \
asm("":"+r"(tmp)); \
tmp; \
@@ -248,7 +254,7 @@
*/
#define ll_start_decl(_sym, _type, _list) \
static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
- __section("__u_boot_list_2_" #_list "_1")
+ __section(ll_start_section_name(_list))
/*
* ll_end_decl uses __aligned(1) to avoid padding before the end marker.
@@ -256,7 +262,7 @@
*/
#define ll_end_decl(_sym, _type, _list) \
static _type _sym[0] __aligned(1) \
- __section("__u_boot_list_2_" #_list "_3")
+ __section(ll_end_section_name(_list))
/**
* ll_entry_get() - Retrieve entry from linker-generated array by name
@@ -281,10 +287,10 @@
*/
#define ll_entry_get(_type, _name, _list) \
({ \
- extern _type _u_boot_list_2_##_list##_2_##_name \
+ extern _type ll_entry_symbol_name(_list, _name) \
__aligned(4); \
_type *_ll_result = \
- &_u_boot_list_2_##_list##_2_##_name; \
+ &ll_entry_symbol_name(_list, _name); \
_ll_result; \
})
@@ -302,7 +308,7 @@
* @_list: name of the list
*/
#define ll_entry_ref(_type, _name, _list) \
- ((_type *)&_u_boot_list_2_##_list##_2_##_name)
+ ((_type *)&ll_entry_symbol_name(_list, _name))
#endif /* __ASSEMBLY__ */
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros
2026-05-22 21:27 ` [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros Rasmus Villemoes
@ 2026-05-22 22:44 ` Tom Rini
2026-05-25 14:32 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Tom Rini @ 2026-05-22 22:44 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 544 bytes --]
On Fri, May 22, 2026 at 11:27:51PM +0200, Rasmus Villemoes wrote:
> Instead of open-coding the same section and symbol naming scheme over
> and over, add helper macros that take the list name (and, for entries,
> the name of the entry/entries) and construct a suitable string
> literal.
>
> This will be particularly important when the followup patches add even
> more uses of those names.
>
> No functional change.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros
2026-05-22 21:27 ` [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros Rasmus Villemoes
2026-05-22 22:44 ` Tom Rini
@ 2026-05-25 14:32 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-25 14:32 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> linker_lists.h: add ll_*_name() helper macros
>
> Instead of open-coding the same section and symbol naming scheme over
> and over, add helper macros that take the list name (and, for entries,
> the name of the entry/entries) and construct a suitable string
> literal.
>
> This will be particularly important when the followup patches add even
> more uses of those names.
>
> No functional change.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
> Reviewed-by: Tom Rini <trini@konsulko.com>
>
> include/linker_lists.h | 30 ++++++++++++++++++------------
> 1 file changed, 18 insertions(+), 12 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (3 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 4/9] linker_lists.h: add ll_*_name() helper macros Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-22 22:44 ` Tom Rini
2026-05-25 15:02 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 6/9] linker_lists.rst: update documentation Rasmus Villemoes
` (3 subsequent siblings)
8 siblings, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
Since commit e2138cf1e60 ("linker_lists.h: drop never used ll_start,
ll_end macros"), which removed macros that would create
__u_boot_list_1 and __u_boot_list_3 sections, the first _2 in the
linker list section names doesn't serve any purpose and is in fact
just confusing. So remove it.
There never seemed to be a reason for the symbol names to have that
_2, other than perhaps for consistency with the section those symbols
belonged to. Regardless, remove that as well.
All linker scripts use a "__u_boot_list*" glob, so they will work just
the same without that common _2.
Keep the _2_ part in the separator between list and entry names for
symbols, since that is called out in the documentation to allow one to
define sublists and iterate over those. I cannot find any current use
of that feature, but a later patch will make use of just that.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/linker_lists.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/linker_lists.h b/include/linker_lists.h
index b6437ad6462..b94e3a359f3 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -19,11 +19,11 @@
#if !defined(__ASSEMBLY__)
-#define ll_start_section_name(_list) "__u_boot_list_2_"#_list"_1"
-#define ll_entry_section_name(_list, _name) "__u_boot_list_2_"#_list"_2_"#_name
-#define ll_end_section_name(_list) "__u_boot_list_2_"#_list"_3"
+#define ll_start_section_name(_list) "__u_boot_list_"#_list"_1"
+#define ll_entry_section_name(_list, _name) "__u_boot_list_"#_list"_2_"#_name
+#define ll_end_section_name(_list) "__u_boot_list_"#_list"_3"
-#define ll_entry_symbol_name(_list, _name) _u_boot_list_2_##_list##_2_##_name
+#define ll_entry_symbol_name(_list, _name) _u_boot_list_##_list##_2_##_name
/**
* llsym() - Access a linker-generated array entry
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix
2026-05-22 21:27 ` [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix Rasmus Villemoes
@ 2026-05-22 22:44 ` Tom Rini
2026-05-25 15:02 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Tom Rini @ 2026-05-22 22:44 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 1085 bytes --]
On Fri, May 22, 2026 at 11:27:52PM +0200, Rasmus Villemoes wrote:
> Since commit e2138cf1e60 ("linker_lists.h: drop never used ll_start,
> ll_end macros"), which removed macros that would create
> __u_boot_list_1 and __u_boot_list_3 sections, the first _2 in the
> linker list section names doesn't serve any purpose and is in fact
> just confusing. So remove it.
>
> There never seemed to be a reason for the symbol names to have that
> _2, other than perhaps for consistency with the section those symbols
> belonged to. Regardless, remove that as well.
>
> All linker scripts use a "__u_boot_list*" glob, so they will work just
> the same without that common _2.
>
> Keep the _2_ part in the separator between list and entry names for
> symbols, since that is called out in the documentation to allow one to
> define sublists and iterate over those. I cannot find any current use
> of that feature, but a later patch will make use of just that.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix
2026-05-22 21:27 ` [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix Rasmus Villemoes
2026-05-22 22:44 ` Tom Rini
@ 2026-05-25 15:02 ` Simon Glass
2026-05-26 21:44 ` Rasmus Villemoes
1 sibling, 1 reply; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:02 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Rasmus,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> linker_lists.h: drop _2 from section and symbol name prefix
>
> Since commit e2138cf1e60 ("linker_lists.h: drop never used ll_start,
> ll_end macros"), which removed macros that would create
> __u_boot_list_1 and __u_boot_list_3 sections, the first _2 in the
> linker list section names doesn't serve any purpose and is in fact
> just confusing. So remove it.
>
> There never seemed to be a reason for the symbol names to have that
> _2, other than perhaps for consistency with the section those symbols
> belonged to. Regardless, remove that as well.
>
> All linker scripts use a '__u_boot_list*' glob, so they will work just
> the same without that common _2.
>
> Keep the _2_ part in the separator between list and entry names for
> symbols, since that is called out in the documentation to allow one to
> define sublists and iterate over those. I cannot find any current use
> of that feature, but a later patch will make use of just that.
>
> [...]
>
> include/linker_lists.h | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -19,11 +19,11 @@
> -#define ll_start_section_name(_list) '__u_boot_list_2_'#_list'_1'
> -#define ll_entry_section_name(_list, _name) '__u_boot_list_2_'#_list'_2_'#_name
> -#define ll_end_section_name(_list) '__u_boot_list_2_'#_list'_3'
> +#define ll_start_section_name(_list) '__u_boot_list_'#_list'_1'
> +#define ll_entry_section_name(_list, _name) '__u_boot_list_'#_list'_2_'#_name
> +#define ll_end_section_name(_list) '__u_boot_list_'#_list'_3'
>
> -#define ll_entry_symbol_name(_list, _name) _u_boot_list_2_##_list##_2_##_name
> +#define ll_entry_symbol_name(_list, _name) _u_boot_list_##_list##_2_##_name
The linker scripts all use a '__u_boot_list*' glob, but several other
places hard-code the old prefix and this patch does not update them:
scripts/gen_ll_addressable_symbols.sh:14 greps for
'_u_boot_list_2_[a-zA-Z0-9_]*_2_[a-zA-Z0-9_]*'
which is fed into the LTO keep-symbols build step (cmd_keep_syms_lto
in the top-level Makefile). With the new names this matches nothing,
so LTO builds silently lose the __ADDRESSABLE() guards.
scripts/event_dump.py hard-codes
PREFIX_FULL = '_u_boot_list_2_evspy_info_2_'
PREFIX_SIMPLE = '_u_boot_list_2_evspy_info_simple_2_'
so the script (and test_event_dump.py) stop finding anything.
test/py/conftest.py has
RE_UT_TEST_LIST =
re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_2_(.*)\s*$')
which is how test.py enumerates ut subtests - this breaks test
discovery for individual UT suites.
There might be others too?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix
2026-05-25 15:02 ` Simon Glass
@ 2026-05-26 21:44 ` Rasmus Villemoes
2026-05-27 4:41 ` Simon Glass
0 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-26 21:44 UTC (permalink / raw)
To: Simon Glass; +Cc: u-boot, Tom Rini
On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
> Hi Rasmus,
>
> On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
>> linker_lists.h: drop _2 from section and symbol name prefix
>>
>> Since commit e2138cf1e60 ("linker_lists.h: drop never used ll_start,
>> ll_end macros"), which removed macros that would create
>> __u_boot_list_1 and __u_boot_list_3 sections, the first _2 in the
>> linker list section names doesn't serve any purpose and is in fact
>> just confusing. So remove it.
>>
>> There never seemed to be a reason for the symbol names to have that
>> _2, other than perhaps for consistency with the section those symbols
>> belonged to. Regardless, remove that as well.
>>
>> All linker scripts use a '__u_boot_list*' glob, so they will work just
>> the same without that common _2.
>>
>> Keep the _2_ part in the separator between list and entry names for
>> symbols, since that is called out in the documentation to allow one to
>> define sublists and iterate over those. I cannot find any current use
>> of that feature, but a later patch will make use of just that.
>>
>> [...]
>>
>> include/linker_lists.h | 8 ++++----
>> 1 file changed, 4 insertions(+), 4 deletions(-)
>
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -19,11 +19,11 @@
>> -#define ll_start_section_name(_list) '__u_boot_list_2_'#_list'_1'
>> -#define ll_entry_section_name(_list, _name) '__u_boot_list_2_'#_list'_2_'#_name
>> -#define ll_end_section_name(_list) '__u_boot_list_2_'#_list'_3'
>> +#define ll_start_section_name(_list) '__u_boot_list_'#_list'_1'
>> +#define ll_entry_section_name(_list, _name) '__u_boot_list_'#_list'_2_'#_name
>> +#define ll_end_section_name(_list) '__u_boot_list_'#_list'_3'
>
>>
>> -#define ll_entry_symbol_name(_list, _name) _u_boot_list_2_##_list##_2_##_name
>> +#define ll_entry_symbol_name(_list, _name) _u_boot_list_##_list##_2_##_name
>
> The linker scripts all use a '__u_boot_list*' glob, but several other
> places hard-code the old prefix and this patch does not update them:
>
> scripts/gen_ll_addressable_symbols.sh:14 greps for
> '_u_boot_list_2_[a-zA-Z0-9_]*_2_[a-zA-Z0-9_]*'
> which is fed into the LTO keep-symbols build step (cmd_keep_syms_lto
> in the top-level Makefile). With the new names this matches nothing,
> so LTO builds silently lose the __ADDRESSABLE() guards.
>
> scripts/event_dump.py hard-codes
> PREFIX_FULL = '_u_boot_list_2_evspy_info_2_'
> PREFIX_SIMPLE = '_u_boot_list_2_evspy_info_simple_2_'
> so the script (and test_event_dump.py) stop finding anything.
>
> test/py/conftest.py has
> RE_UT_TEST_LIST =
> re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_2_(.*)\s*$')
> which is how test.py enumerates ut subtests - this breaks test
> discovery for individual UT suites.
Ah yes, thanks. I wonder how I could miss those.
They are of course all trivial to update. But for the
gen_ll_addressable_symbols.sh script, I do wonder why the __ADDRESSABLE
wasn't just made part of the ll macros. It has since grown another
__stack_chk_guard, but that too should be able to just have its
ADDRESSABLE marking in the (ordinary C) TU that defines it.
Rasmus
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix
2026-05-26 21:44 ` Rasmus Villemoes
@ 2026-05-27 4:41 ` Simon Glass
0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-27 4:41 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Tom Rini
Hi Rasmus,
On Tue, 26 May 2026 at 15:44, Rasmus Villemoes <ravi@prevas.dk> wrote:
>
> On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
>
> > Hi Rasmus,
> >
> > On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> >> linker_lists.h: drop _2 from section and symbol name prefix
> >>
> >> Since commit e2138cf1e60 ("linker_lists.h: drop never used ll_start,
> >> ll_end macros"), which removed macros that would create
> >> __u_boot_list_1 and __u_boot_list_3 sections, the first _2 in the
> >> linker list section names doesn't serve any purpose and is in fact
> >> just confusing. So remove it.
> >>
> >> There never seemed to be a reason for the symbol names to have that
> >> _2, other than perhaps for consistency with the section those symbols
> >> belonged to. Regardless, remove that as well.
> >>
> >> All linker scripts use a '__u_boot_list*' glob, so they will work just
> >> the same without that common _2.
> >>
> >> Keep the _2_ part in the separator between list and entry names for
> >> symbols, since that is called out in the documentation to allow one to
> >> define sublists and iterate over those. I cannot find any current use
> >> of that feature, but a later patch will make use of just that.
> >>
> >> [...]
> >>
> >> include/linker_lists.h | 8 ++++----
> >> 1 file changed, 4 insertions(+), 4 deletions(-)
> >
> >> diff --git a/include/linker_lists.h b/include/linker_lists.h
> >> @@ -19,11 +19,11 @@
> >> -#define ll_start_section_name(_list) '__u_boot_list_2_'#_list'_1'
> >> -#define ll_entry_section_name(_list, _name) '__u_boot_list_2_'#_list'_2_'#_name
> >> -#define ll_end_section_name(_list) '__u_boot_list_2_'#_list'_3'
> >> +#define ll_start_section_name(_list) '__u_boot_list_'#_list'_1'
> >> +#define ll_entry_section_name(_list, _name) '__u_boot_list_'#_list'_2_'#_name
> >> +#define ll_end_section_name(_list) '__u_boot_list_'#_list'_3'
> >
> >>
> >> -#define ll_entry_symbol_name(_list, _name) _u_boot_list_2_##_list##_2_##_name
> >> +#define ll_entry_symbol_name(_list, _name) _u_boot_list_##_list##_2_##_name
> >
> > The linker scripts all use a '__u_boot_list*' glob, but several other
> > places hard-code the old prefix and this patch does not update them:
> >
> > scripts/gen_ll_addressable_symbols.sh:14 greps for
> > '_u_boot_list_2_[a-zA-Z0-9_]*_2_[a-zA-Z0-9_]*'
> > which is fed into the LTO keep-symbols build step (cmd_keep_syms_lto
> > in the top-level Makefile). With the new names this matches nothing,
> > so LTO builds silently lose the __ADDRESSABLE() guards.
> >
>
> > scripts/event_dump.py hard-codes
> > PREFIX_FULL = '_u_boot_list_2_evspy_info_2_'
> > PREFIX_SIMPLE = '_u_boot_list_2_evspy_info_simple_2_'
> > so the script (and test_event_dump.py) stop finding anything.
> >
> > test/py/conftest.py has
> > RE_UT_TEST_LIST =
> > re.compile(r'[^a-zA-Z0-9_]_u_boot_list_2_ut_(.*)_2_(.*)\s*$')
> > which is how test.py enumerates ut subtests - this breaks test
> > discovery for individual UT suites.
>
> Ah yes, thanks. I wonder how I could miss those.
>
> They are of course all trivial to update. But for the
> gen_ll_addressable_symbols.sh script, I do wonder why the __ADDRESSABLE
> wasn't just made part of the ll macros. It has since grown another
> __stack_chk_guard, but that too should be able to just have its
> ADDRESSABLE marking in the (ordinary C) TU that defines it.
I'm not really sure, but perhaps it was so that the same mechanism
could be used for all such symbols, avoiding __ADDRESSABLE bleeding
out into the rest of the code?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 6/9] linker_lists.rst: update documentation
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (4 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 5/9] linker_lists.h: drop _2 from section and symbol name prefix Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-22 22:45 ` Tom Rini
2026-05-25 15:03 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 7/9] test: avoid use of special characters in ELF section names Rasmus Villemoes
` (2 subsequent siblings)
8 siblings, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
Remove the initial _2 component in the examples in order to match what
linker_lists.h now does. This also makes the
Note the two '_2_' constant components in the names
easier to grok, as there is now only one such component.
Remove the whole "Start and end symbols for the whole of the linker
lists area can be defined as" paragraph, since that can no longer be
done like that, and the (never used) macros doing it were removed in
e2138cf1e60 ("linker_lists.h: drop never used ll_start, ll_end
macros").
Leave the occurrences in the "Alignment issues" subsection alone for
now. They are verbatim copies from a u-boot.map file, and it would not
be right to edit that long after the fact, when we cannot easily
reproduce a u-boot.map exhibiting this phenomenon.
Part of the purpose of this series is to get a better handle on
alignment issues once and for all, so hopefully we can simply remove
the whole subsection in a not too distant future.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
doc/api/linker_lists.rst | 54 +++++++++++++++++-----------------------
1 file changed, 23 insertions(+), 31 deletions(-)
diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
index 9e6849d5e75..3f7a982c518 100644
--- a/doc/api/linker_lists.rst
+++ b/doc/api/linker_lists.rst
@@ -13,13 +13,13 @@ then the corresponding input section name is
::
- __u_boot_list_ + 2_ + @_list + _2_ + @_entry
+ __u_boot_list_ + @_list + _2_ + @_entry
and the C variable name is
::
- _u_boot_list + _2_ + @_list + _2_ + @_entry
+ _u_boot_list + @_list + _2_ + @_entry
This ensures uniqueness for both input section and C variable name.
@@ -30,7 +30,7 @@ to as
::
- %u_boot_list_ + 2_ + @_list + _2_ + @_entry
+ %u_boot_list_ + @_list + _2_ + @_entry
Entry variables need never be referred to directly.
@@ -46,16 +46,8 @@ Start and end symbols for a list can generally be defined as
::
- %u_boot_list_2_ + @_list + _1_...
- %u_boot_list_2_ + @_list + _3_...
-
-Start and end symbols for the whole of the linker lists area can be
-defined as
-
-::
-
- %u_boot_list_1_...
- %u_boot_list_3_...
+ %u_boot_list_ + @_list + _1_...
+ %u_boot_list_ + @_list + _3_...
Here is an example of the sorted sections which result from a list
"array" made up of three entries : "first", "second" and "third",
@@ -63,11 +55,11 @@ iterated at least once.
::
- __u_boot_list_2_array_1
- __u_boot_list_2_array_2_first
- __u_boot_list_2_array_2_second
- __u_boot_list_2_array_2_third
- __u_boot_list_2_array_3
+ __u_boot_list_array_1
+ __u_boot_list_array_2_first
+ __u_boot_list_array_2_second
+ __u_boot_list_array_2_third
+ __u_boot_list_array_3
If lists must be divided into sublists (e.g. for iterating only on
part of a list), one can simply give the list a name of the form
@@ -82,19 +74,19 @@ defined for the whole list and each sub-list:
::
- %u_boot_list_2_drivers_1
- %u_boot_list_2_drivers_2_i2c_1
- %u_boot_list_2_drivers_2_i2c_2_first
- %u_boot_list_2_drivers_2_i2c_2_first
- %u_boot_list_2_drivers_2_i2c_2_second
- %u_boot_list_2_drivers_2_i2c_2_third
- %u_boot_list_2_drivers_2_i2c_3
- %u_boot_list_2_drivers_2_pci_1
- %u_boot_list_2_drivers_2_pci_2_first
- %u_boot_list_2_drivers_2_pci_2_second
- %u_boot_list_2_drivers_2_pci_2_third
- %u_boot_list_2_drivers_2_pci_3
- %u_boot_list_2_drivers_3
+ %u_boot_list_drivers_1
+ %u_boot_list_drivers_2_i2c_1
+ %u_boot_list_drivers_2_i2c_2_first
+ %u_boot_list_drivers_2_i2c_2_first
+ %u_boot_list_drivers_2_i2c_2_second
+ %u_boot_list_drivers_2_i2c_2_third
+ %u_boot_list_drivers_2_i2c_3
+ %u_boot_list_drivers_2_pci_1
+ %u_boot_list_drivers_2_pci_2_first
+ %u_boot_list_drivers_2_pci_2_second
+ %u_boot_list_drivers_2_pci_2_third
+ %u_boot_list_drivers_2_pci_3
+ %u_boot_list_drivers_3
Alignment issues
----------------
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 6/9] linker_lists.rst: update documentation
2026-05-22 21:27 ` [RFC PATCH 6/9] linker_lists.rst: update documentation Rasmus Villemoes
@ 2026-05-22 22:45 ` Tom Rini
2026-05-25 15:03 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Tom Rini @ 2026-05-22 22:45 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 1381 bytes --]
On Fri, May 22, 2026 at 11:27:53PM +0200, Rasmus Villemoes wrote:
> Remove the initial _2 component in the examples in order to match what
> linker_lists.h now does. This also makes the
>
> Note the two '_2_' constant components in the names
>
> easier to grok, as there is now only one such component.
>
> Remove the whole "Start and end symbols for the whole of the linker
> lists area can be defined as" paragraph, since that can no longer be
> done like that, and the (never used) macros doing it were removed in
> e2138cf1e60 ("linker_lists.h: drop never used ll_start, ll_end
> macros").
>
> Leave the occurrences in the "Alignment issues" subsection alone for
> now. They are verbatim copies from a u-boot.map file, and it would not
> be right to edit that long after the fact, when we cannot easily
> reproduce a u-boot.map exhibiting this phenomenon.
>
> Part of the purpose of this series is to get a better handle on
> alignment issues once and for all, so hopefully we can simply remove
> the whole subsection in a not too distant future.
Thank you for digging more at this. I really look forward to unravelling
some of the less clear parts of this implementation and either being
able to remove the align(1)/align(4)s throughout or much better document
why we need them and what their values should be because of this.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 6/9] linker_lists.rst: update documentation
2026-05-22 21:27 ` [RFC PATCH 6/9] linker_lists.rst: update documentation Rasmus Villemoes
2026-05-22 22:45 ` Tom Rini
@ 2026-05-25 15:03 ` Simon Glass
2026-05-26 21:49 ` Rasmus Villemoes
1 sibling, 1 reply; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:03 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Rasmus,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> linker_lists.rst: update documentation
>
> Remove the initial _2 component in the examples in order to match what
> linker_lists.h now does. This also makes the
>
> Note the two '_2_' constant components in the names
>
> easier to grok, as there is now only one such component.
>
> Remove the whole "Start and end symbols for the whole of the linker
> lists area can be defined as" paragraph, since that can no longer be
> done like that, and the (never used) macros doing it were removed in
> e2138cf1e60 ("linker_lists.h: drop never used ll_start, ll_end
> macros").
>
> Leave the occurrences in the "Alignment issues" subsection alone for
> now. They are verbatim copies from a u-boot.map file, and it would not
> be right to edit that long after the fact, when we cannot easily
> reproduce a u-boot.map exhibiting this phenomenon.
>
> [...]
>
> doc/api/linker_lists.rst | 54 +++++++++++++++++++++---------------------------
> 1 file changed, 23 insertions(+), 31 deletions(-)
> diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
> @@ -13,13 +13,13 @@ then the corresponding input section name is
>
> ::
>
> - __u_boot_list_ + 2_ + @_list + _2_ + @_entry
> + __u_boot_list_ + @_list + _2_ + @_entry
>
> and the C variable name is
>
> ::
>
> - _u_boot_list + _2_ + @_list + _2_ + @_entry
> + _u_boot_list + @_list + _2_ + @_entry
Not quite - the actual symbol is _u_boot_list_##_list##_2_##_name
(note the trailing underscore on the prefix), so for list 'drivers'
and entry 'first' the name expands to _u_boot_list_drivers_2_first
As written here, the components concatenate to
_u_boot_listdrivers_2_first - please change to:
_u_boot_list_ + @_list + _2_ + @_entry
to match the section line above and the unified '%u_boot_list_ + ...'
form a few lines later.
> diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
> @@ -46,16 +46,8 @@ Start and end symbols for a list can generally be defined as
>
> ::
>
> - %u_boot_list_2_ + @_list + _1_...
> - %u_boot_list_2_ + @_list + _3_...
> -
> -Start and end symbols for the whole of the linker lists area can be
> -defined as
> -
> -::
> -
> - %u_boot_list_1_...
> - %u_boot_list_3_...
> + %u_boot_list_ + @_list + _1_...
> + %u_boot_list_ + @_list + _3_...
The commit message says the surrounding 'Note the two _2_ constant
components' paragraph is now easier to grok because only one such
component remains, but the paragraph itself still says 'two' in the
patched file. Please update it to say 'one' and adjust the rest of the
sentence, since the start/end mapping is now relative to the single
_2_ separator between list and entry.
> diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
> @@ -82,19 +74,19 @@ defined for the whole list and each sub-list:
> - %u_boot_list_2_drivers_2_i2c_2_first
> - %u_boot_list_2_drivers_2_i2c_2_first
> - %u_boot_list_2_drivers_2_i2c_2_second
> + %u_boot_list_drivers_2_i2c_1
> + %u_boot_list_drivers_2_i2c_2_first
> + %u_boot_list_drivers_2_i2c_2_first
> + %u_boot_list_drivers_2_i2c_2_second
BTW '...i2c_2_first' is listed twice - please drop the duplicate at
the same time.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 6/9] linker_lists.rst: update documentation
2026-05-25 15:03 ` Simon Glass
@ 2026-05-26 21:49 ` Rasmus Villemoes
0 siblings, 0 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-26 21:49 UTC (permalink / raw)
To: Simon Glass; +Cc: u-boot, Tom Rini
On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
>>
>> - __u_boot_list_ + 2_ + @_list + _2_ + @_entry
>> + __u_boot_list_ + @_list + _2_ + @_entry
>>
>> and the C variable name is
>>
>> ::
>>
>> - _u_boot_list + _2_ + @_list + _2_ + @_entry
>> + _u_boot_list + @_list + _2_ + @_entry
>
> Not quite - the actual symbol is _u_boot_list_##_list##_2_##_name
> (note the trailing underscore on the prefix), so for list 'drivers'
> and entry 'first' the name expands to _u_boot_list_drivers_2_first
>
> As written here, the components concatenate to
> _u_boot_listdrivers_2_first - please change to:
>
> _u_boot_list_ + @_list + _2_ + @_entry
>
> to match the section line above and the unified '%u_boot_list_ + ...'
> form a few lines later.
Good catch, I hadn't noticed the inconsistency in how the existing
section versus symbol names were documented.
>> diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
>> @@ -46,16 +46,8 @@ Start and end symbols for a list can generally be defined as
>>
>> ::
>>
>> - %u_boot_list_2_ + @_list + _1_...
>> - %u_boot_list_2_ + @_list + _3_...
>> -
>> -Start and end symbols for the whole of the linker lists area can be
>> -defined as
>> -
>> -::
>> -
>> - %u_boot_list_1_...
>> - %u_boot_list_3_...
>> + %u_boot_list_ + @_list + _1_...
>> + %u_boot_list_ + @_list + _3_...
>
> The commit message says the surrounding 'Note the two _2_ constant
> components' paragraph is now easier to grok because only one such
> component remains, but the paragraph itself still says 'two' in the
> patched file. Please update it to say 'one' and adjust the rest of the
> sentence, since the start/end mapping is now relative to the single
> _2_ separator between list and entry.
Ah, yes, that does require rewording to make sense.
>> diff --git a/doc/api/linker_lists.rst b/doc/api/linker_lists.rst
>> @@ -82,19 +74,19 @@ defined for the whole list and each sub-list:
>> - %u_boot_list_2_drivers_2_i2c_2_first
>> - %u_boot_list_2_drivers_2_i2c_2_first
>> - %u_boot_list_2_drivers_2_i2c_2_second
>> + %u_boot_list_drivers_2_i2c_1
>> + %u_boot_list_drivers_2_i2c_2_first
>> + %u_boot_list_drivers_2_i2c_2_first
>> + %u_boot_list_drivers_2_i2c_2_second
>
> BTW '...i2c_2_first' is listed twice - please drop the duplicate at
> the same time.
>
Will do.
Thanks,
Rasmus
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 7/9] test: avoid use of special characters in ELF section names
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (5 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 6/9] linker_lists.rst: update documentation Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-22 22:45 ` Tom Rini
2026-05-25 15:03 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking Rasmus Villemoes
2026-05-22 21:27 ` [RFC PATCH 9/9] tools: add linker-lists.py parser/checker script Rasmus Villemoes
8 siblings, 2 replies; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
While the use of the ! and ~ characters currently works, it is a bit
hacky, and conflicts with later patches that will require the
arguments to ll_entry_start() to be allowed at least as assembly
identifiers.
linker_lists.rst actually describes how one can do what the test
framework wants to do: We have one "outer" list, ut, with individual
"inner" lists (each suite). In order to be able to delineate the outer
list using the ordinary ll_ helpers, we just have to make sure that
all the inner lists use the section name ut_2_<suite> instead of
ut_<suite>.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/test/test.h | 15 +++++++--------
test/cmd_ut.c | 4 ++--
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/include/test/test.h b/include/test/test.h
index 0f2b68a5dee..6423f3486be 100644
--- a/include/test/test.h
+++ b/include/test/test.h
@@ -142,7 +142,7 @@ struct unit_test {
* @_suite: name of the test suite concatenated with "_test"
*/
#define UNIT_TEST(_name, _flags, _suite) \
- ll_entry_declare(struct unit_test, _name, ut_ ## _suite) = { \
+ ll_entry_declare(struct unit_test, _name, ut_2_ ## _suite) = { \
.file = __FILE__, \
.name = #_name, \
.flags = _flags, \
@@ -151,7 +151,7 @@ struct unit_test {
/* init function for unit-test suite (the 'A' makes it first) */
#define UNIT_TEST_INIT(_name, _flags, _suite) \
- ll_entry_declare(struct unit_test, A ## _name, ut_ ## _suite) = { \
+ ll_entry_declare(struct unit_test, A ## _name, ut_2_ ## _suite) = { \
.file = __FILE__, \
.name = #_name, \
.flags = (_flags) | UTF_INIT, \
@@ -160,7 +160,7 @@ struct unit_test {
/* uninit function for unit-test suite (the 'aaa' makes it last) */
#define UNIT_TEST_UNINIT(_name, _flags, _suite) \
- ll_entry_declare(struct unit_test, zzz ## _name, ut_ ## _suite) = { \
+ ll_entry_declare(struct unit_test, zzz ## _name, ut_2_ ## _suite) = { \
.file = __FILE__, \
.name = #_name, \
.flags = (_flags) | UTF_UNINIT, \
@@ -169,13 +169,12 @@ struct unit_test {
/* Get the start of a list of unit tests for a particular suite */
#define UNIT_TEST_SUITE_START(_suite) \
- ll_entry_start(struct unit_test, ut_ ## _suite)
+ ll_entry_start(struct unit_test, ut_2_ ## _suite)
#define UNIT_TEST_SUITE_COUNT(_suite) \
- ll_entry_count(struct unit_test, ut_ ## _suite)
+ ll_entry_count(struct unit_test, ut_2_ ## _suite)
-/* Use ! and ~ so that all tests will be sorted between these two values */
-#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut_!)
-#define UNIT_TEST_ALL_END() ll_entry_start(struct unit_test, ut_~)
+#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut)
+#define UNIT_TEST_ALL_END() ll_entry_end(struct unit_test, ut)
#define UNIT_TEST_ALL_COUNT() (UNIT_TEST_ALL_END() - UNIT_TEST_ALL_START())
/* Sizes for devres tests */
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 44e5fdfdaa6..9d74f091138 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -36,8 +36,8 @@ static int do_ut_info(bool show_suites);
/* declare linker-list symbols for the start and end of a suite */
#define SUITE_DECL(_name) \
- ll_start_decl(suite_start_ ## _name, struct unit_test, ut_ ## _name); \
- ll_end_decl(suite_end_ ## _name, struct unit_test, ut_ ## _name)
+ ll_start_decl(suite_start_ ## _name, struct unit_test, ut_2_ ## _name); \
+ ll_end_decl(suite_end_ ## _name, struct unit_test, ut_2_ ## _name)
/* declare a test suite which can be run directly without a subcommand */
#define SUITE(_name, _help) { \
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 7/9] test: avoid use of special characters in ELF section names
2026-05-22 21:27 ` [RFC PATCH 7/9] test: avoid use of special characters in ELF section names Rasmus Villemoes
@ 2026-05-22 22:45 ` Tom Rini
2026-05-25 15:03 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Tom Rini @ 2026-05-22 22:45 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 776 bytes --]
On Fri, May 22, 2026 at 11:27:54PM +0200, Rasmus Villemoes wrote:
> While the use of the ! and ~ characters currently works, it is a bit
> hacky, and conflicts with later patches that will require the
> arguments to ll_entry_start() to be allowed at least as assembly
> identifiers.
>
> linker_lists.rst actually describes how one can do what the test
> framework wants to do: We have one "outer" list, ut, with individual
> "inner" lists (each suite). In order to be able to delineate the outer
> list using the ordinary ll_ helpers, we just have to make sure that
> all the inner lists use the section name ut_2_<suite> instead of
> ut_<suite>.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
Reviewed-by: Tom Rini <trini@konsulko.com>
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 32+ messages in thread
* Re: [RFC PATCH 7/9] test: avoid use of special characters in ELF section names
2026-05-22 21:27 ` [RFC PATCH 7/9] test: avoid use of special characters in ELF section names Rasmus Villemoes
2026-05-22 22:45 ` Tom Rini
@ 2026-05-25 15:03 ` Simon Glass
1 sibling, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:03 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Rasmus,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> test: avoid use of special characters in ELF section names
>
> While the use of the ! and ~ characters currently works, it is a bit
> hacky, and conflicts with later patches that will require the
> arguments to ll_entry_start() to be allowed at least as assembly
> identifiers.
>
> linker_lists.rst actually describes how one can do what the test
> framework wants to do: We have one 'outer' list, ut, with individual
> 'inner' lists (each suite). In order to be able to delineate the outer
> list using the ordinary ll_ helpers, we just have to make sure that
> all the inner lists use the section name ut_2_<suite> instead of
> ut_<suite>.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
> Reviewed-by: Tom Rini <trini@konsulko.com>
>
> include/test/test.h | 15 +++++++--------
> test/cmd_ut.c | 4 ++--
> 2 files changed, 9 insertions(+), 10 deletions(-)
> diff --git a/include/test/test.h b/include/test/test.h
> @@ -169,13 +169,12 @@ struct unit_test {
>
> /* Get the start of a list of unit tests for a particular suite */
> #define UNIT_TEST_SUITE_START(_suite) \
> - ll_entry_start(struct unit_test, ut_ ## _suite)
> + ll_entry_start(struct unit_test, ut_2_ ## _suite)
> #define UNIT_TEST_SUITE_COUNT(_suite) \
> - ll_entry_count(struct unit_test, ut_ ## _suite)
> + ll_entry_count(struct unit_test, ut_2_ ## _suite)
>
> -/* Use ! and ~ so that all tests will be sorted between these two values */
> -#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut_!)
> -#define UNIT_TEST_ALL_END() ll_entry_start(struct unit_test, ut_~)
> +#define UNIT_TEST_ALL_START() ll_entry_start(struct unit_test, ut)
> +#define UNIT_TEST_ALL_END() ll_entry_end(struct unit_test, ut)
Each suite symbol now becomes _u_boot_list_ut_2_<suite>_2_<name>, so
the regex in test/py/conftest.py (already broken by patch 5) needs
further adjusting to capture the suite correctly.
generate_ut_subtest() and the docstring above UNIT_TEST() that calls
out the strict naming convention need updating in lockstep, otherwise
test_ut.py / test_spl.py / test_vpl.py silently stop generating
subtests.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (6 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 7/9] test: avoid use of special characters in ELF section names Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-25 14:28 ` Simon Glass
2026-05-22 21:27 ` [RFC PATCH 9/9] tools: add linker-lists.py parser/checker script Rasmus Villemoes
8 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
This is an attempt at to make it possible to catch various problems
with linker lists at build time, without affecting the size of the
final binary. Also, I did not want to have to modify all the linker
scripts in order to not get all this meta-data thrown away by garbage
collection.
The basic trick is that one can use the .size assembly directive so
set the st_size of an ELF symbol, without that symbol actually
occupying that amount of space in any section or the final binary. And
all of the .size, .type, .{push,pop}section directives are completely
generic, so this should work for all architecture.
So whenever we declare a start or end symbol for use by C code, also
emit information about the size and alignment of the type that the
list is supposed to be made of.
A relatively straight-forward script (next patch) can then parse the
ELF file and report on any inconsistencies. For example, suppose two
different translation units happen to use the same identifier for
their list names, with different types. I.e. we have
// abc.c
struct abc { int abc; };
...
ll_entry_start(struct abc, letters);
// xyz.c
struct xyz { long x, y, z; };
...
ll_entry_start(struct xyz, letters);
This is currently not caught at build-time, but will definitely not
work well at run-time.
Similarly, if the compiler or linker ends up doing unexpected things
with respect to aligning either the start/end symbols or one of the
items in the list, we do not catch at build-time that there is a
non-integer number of elements between start and end.
I do not yet know how this behaves wrt LTO, nor do I know how
expensive it would be to always run the sanity checker script at
build-time - if it's too time-consuming or not robust enough, it will
have to be behind a CONFIG option. But I do hope that this should
provide a way to give us some confidence in dropping some of the magic
alignment attributes and the whole CONFIG_LINKER_LIST_ALIGN.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
include/linker_lists.h | 43 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/include/linker_lists.h b/include/linker_lists.h
index b94e3a359f3..2475ac3deaf 100644
--- a/include/linker_lists.h
+++ b/include/linker_lists.h
@@ -11,6 +11,7 @@
#define __LINKER_LISTS_H__
#include <linux/compiler.h>
+#include <linux/stringify.h>
/*
* There is no use in including this from ASM files.
@@ -23,7 +24,45 @@
#define ll_entry_section_name(_list, _name) "__u_boot_list_"#_list"_2_"#_name
#define ll_end_section_name(_list) "__u_boot_list_"#_list"_3"
+#define ll_start_symbol_name(_list) _u_boot_list_##_list##_1_start
#define ll_entry_symbol_name(_list, _name) _u_boot_list_##_list##_2_##_name
+#define ll_end_symbol_name(_list) _u_boot_list_##_list##_3_end
+
+#define ll_info_section_name(_list) "__u_boot_list_"#_list"_0"
+#define ll_size_symbol_name(_list) "_u_boot_list_"#_list"_0_item_size"
+#define ll_align_symbol_name(_list) "_u_boot_list_"#_list"_0_item_align"
+
+#define ll_emit_type_info(_list, _type) \
+ __asm__( \
+ ".pushsection "ll_info_section_name(_list)",\"aw\"\n" \
+ ".type "ll_size_symbol_name(_list)", STT_OBJECT\n" \
+ ".size "ll_size_symbol_name(_list)", %c0\n" \
+ ".type "ll_align_symbol_name(_list)", STT_OBJECT\n" \
+ ".size "ll_align_symbol_name(_list)", %c1\n" \
+ ll_size_symbol_name(_list)":\n" \
+ ll_align_symbol_name(_list)":\n" \
+ ".popsection\n" \
+ : : "i"(sizeof(_type)), "i"(__alignof__(_type)))
+
+#define ll_emit_start_symbol(_list, _type) \
+ ll_emit_type_info(_list, _type); \
+ __asm__( \
+ ".pushsection "ll_start_section_name(_list)",\"aw\"\n" \
+ ".type "__stringify(ll_start_symbol_name(_list))", STT_OBJECT\n" \
+ ".size "__stringify(ll_start_symbol_name(_list))", 0\n" \
+ __stringify(ll_start_symbol_name(_list))":\n" \
+ ".popsection\n" \
+ )
+
+#define ll_emit_end_symbol(_list, _type) \
+ ll_emit_type_info(_list, _type); \
+ __asm__( \
+ ".pushsection "ll_end_section_name(_list)",\"aw\"\n" \
+ ".type "__stringify(ll_end_symbol_name(_list))", STT_OBJECT\n" \
+ ".size "__stringify(ll_end_symbol_name(_list))", 0\n" \
+ __stringify(ll_end_symbol_name(_list))":\n" \
+ ".popsection\n" \
+ )
/**
* llsym() - Access a linker-generated array entry
@@ -128,6 +167,7 @@
*/
#define ll_entry_start(_type, _list) \
({ \
+ ll_emit_start_symbol(_list, _type); \
static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
__section(ll_start_section_name(_list)); \
_type * tmp = (_type *)&start; \
@@ -170,6 +210,7 @@
*/
#define ll_entry_end(_type, _list) \
({ \
+ ll_emit_end_symbol(_list, _type); \
static char end[0] __aligned(1) \
__section(ll_end_section_name(_list)); \
_type * tmp = (_type *)&end; \
@@ -253,6 +294,7 @@
* start of the bob sub-commands. It is then used in my_list[]
*/
#define ll_start_decl(_sym, _type, _list) \
+ ll_emit_start_symbol(_list, _type); \
static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
__section(ll_start_section_name(_list))
@@ -261,6 +303,7 @@
* See the comment for ll_entry_end() for a full explanation.
*/
#define ll_end_decl(_sym, _type, _list) \
+ ll_emit_end_symbol(_list, _type); \
static _type _sym[0] __aligned(1) \
__section(ll_end_section_name(_list))
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking
2026-05-22 21:27 ` [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking Rasmus Villemoes
@ 2026-05-25 14:28 ` Simon Glass
2026-05-26 22:26 ` Rasmus Villemoes
0 siblings, 1 reply; 32+ messages in thread
From: Simon Glass @ 2026-05-25 14:28 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Rasmus,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> linker_lists.h: emit lots of meta-data for debugging and sanity checking
>
> This is an attempt at to make it possible to catch various problems
> with linker lists at build time, without affecting the size of the
> final binary. Also, I did not want to have to modify all the linker
> scripts in order to not get all this meta-data thrown away by garbage
> collection.
>
> The basic trick is that one can use the .size assembly directive so
> set the st_size of an ELF symbol, without that symbol actually
> occupying that amount of space in any section or the final binary. And
> all of the .size, .type, .{push,pop}section directives are completely
> generic, so this should work for all architecture.
>
> So whenever we declare a start or end symbol for use by C code, also
> emit information about the size and alignment of the type that the
> list is supposed to be made of.
>
> A relatively straight-forward script (next patch) can then parse the
> ELF file and report on any inconsistencies. For example, suppose two
> [...]
>
> include/linker_lists.h | 43 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 43 insertions(+)
I see this:
test/cmd_ut.c:67:1: note: in expansion of macro ‘SUITE_DECL’
67 | SUITE_DECL(mbr);
| ^~~~~~~~~~
include/linker_lists.h:45:17: error: expected ‘)’ before ‘:’ token
45 | : : "i"(sizeof(_type)), "i"(__alignof__(_type)))
| ^
include/linker_lists.h:48:9: note: in expansion of macro ‘ll_emit_type_info’
48 | ll_emit_type_info(_list, _type);
\
| ^~~~~~~~~~~~~~~~~
include/linker_lists.h:297:9: note: in expansion of macro ‘ll_emit_start_symbol’
297 | ll_emit_start_symbol(_list, _type);
\
| ^~~~~~~~~~~~~~~~~~~~
See below
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -23,7 +24,45 @@
> +#define ll_emit_type_info(_list, _type) \
> + __asm__( \
> + ".pushsection "ll_info_section_name(_list)',\'aw\'\n' \
> + ".type "ll_size_symbol_name(_list)", STT_OBJECT\n" \
> + ".size "ll_size_symbol_name(_list)", %c0\n" \
> + ".type "ll_align_symbol_name(_list)", STT_OBJECT\n" \
> + ".size "ll_align_symbol_name(_list)", %c1\n" \
> + ll_size_symbol_name(_list)':\n' \
> + ll_align_symbol_name(_list)':\n' \
> + '.popsection\n' \
> + : : 'i'(sizeof(_type)), 'i'(__alignof__(_type)))
This is extended asm (it has operand constraints), so GCC requires it
to be inside a function. ll_start_decl()/ll_end_decl() pull this into
ll_emit_start_symbol/ll_emit_end_symbol at file scope - see
SUITE_DECL() in test/cmd_ut.c
One way out is to drop the operands and have the C side emit a
zero-initialised marker object whose array dimensions encode
sizeof/__alignof__ - e.g. a static struct in a dedicated section whose
two members are sized sizeof(_type) and __alignof__(_type). That costs
a few bytes per list per TU but keeps the trick working at file scope.
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -23,7 +24,45 @@
> +#define ll_emit_start_symbol(_list, _type) \
> + ll_emit_type_info(_list, _type); \
> + __asm__( \
> + ".pushsection "ll_start_section_name(_list)',\'aw\'\n' \
> + ".type "__stringify(ll_start_symbol_name(_list))", STT_OBJECT\n" \
> + ".size "__stringify(ll_start_symbol_name(_list))", 0\n" \
> + __stringify(ll_start_symbol_name(_list))':\n' \
> + '.popsection\n' \
> + )
These multi-statement macros are not wrapped, so they only work in
contexts that accept two declarations/statements separated by ';'.
ll_start_decl() then chains another declaration after them, leaving a
stray ';' at file scope - accepted as a GCC extension but rejected
under -Wpedantic. Please either fold the two asm blocks into one (a
single .pushsection ... .popsection can contain all the
.type/.size/label directives), or wrap them in a way that gives a
single declaration/statement. The latter is awkward at file scope,
which is another argument for the single-asm approach.
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -23,7 +24,45 @@
> +#define ll_info_section_name(_list) '__u_boot_list_'#_list'_0'
Worth mentioning in the commit message that this is matched by the
existing KEEP(*(SORT(__u_boot_list*))) globs in all the linker
scripts, so the new _0 sections end up in the linker_list region of
the final image. Since each section is zero bytes that does not affect
binary size, but it does mean the metadata is reachable from the ELF
symtab without changing any board's linker script - which is exactly
what you say you wanted.
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -23,7 +24,45 @@
> +#define ll_info_section_name(_list) '__u_boot_list_'#_list'_0'
> +#define ll_size_symbol_name(_list) '_u_boot_list_'#_list'_0_item_size'
> +#define ll_align_symbol_name(_list) '_u_boot_list_'#_list'_0_item_align'
The size/align symbols are emitted as local labels, so every TU that
touches a given list contributes its own local copy. That is fine for
the parser in patch 9, but it relies on strip/objcopy not throwing
away local symbols on the way to the final image. A note about this -
or about pointing the script at u-boot (the unstripped ELF) rather
than u-boot.bin - would help anyone trying this themselves.
> diff --git a/include/linker_lists.h b/include/linker_lists.h
> @@ -128,6 +167,7 @@
> #define ll_entry_start(_type, _list) \
> ({ \
> + ll_emit_start_symbol(_list, _type); \
> static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
> __section(ll_start_section_name(_list)); \
Just to check: is there any reason ll_entry_start() emits the metadata
at every call site rather than only where the start/end markers are
first defined? Within a given TU every call expands to the same
.size/.type for the same symbol, which the assembler tolerates but is
wasted work. If you can move it into the declarations themselves (or
use a once-per-TU guard) the diff for existing call sites stays the
same and the assembler output gets much smaller.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking
2026-05-25 14:28 ` Simon Glass
@ 2026-05-26 22:26 ` Rasmus Villemoes
2026-05-26 22:41 ` Rasmus Villemoes
0 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-26 22:26 UTC (permalink / raw)
To: Simon Glass; +Cc: u-boot, Tom Rini
On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
> Hi Rasmus,
>
> On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
>> linker_lists.h: emit lots of meta-data for debugging and sanity checking
>>
>> This is an attempt at to make it possible to catch various problems
>> with linker lists at build time, without affecting the size of the
>> final binary. Also, I did not want to have to modify all the linker
>> scripts in order to not get all this meta-data thrown away by garbage
>> collection.
>>
>> The basic trick is that one can use the .size assembly directive so
>> set the st_size of an ELF symbol, without that symbol actually
>> occupying that amount of space in any section or the final binary. And
>> all of the .size, .type, .{push,pop}section directives are completely
>> generic, so this should work for all architecture.
>>
>> So whenever we declare a start or end symbol for use by C code, also
>> emit information about the size and alignment of the type that the
>> list is supposed to be made of.
>>
>> A relatively straight-forward script (next patch) can then parse the
>> ELF file and report on any inconsistencies. For example, suppose two
>> [...]
>>
>> include/linker_lists.h | 43 +++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 43 insertions(+)
>
> I see this:
>
> test/cmd_ut.c:67:1: note: in expansion of macro ‘SUITE_DECL’
> 67 | SUITE_DECL(mbr);
> | ^~~~~~~~~~
> include/linker_lists.h:45:17: error: expected ‘)’ before ‘:’ token
> 45 | : : "i"(sizeof(_type)), "i"(__alignof__(_type)))
> | ^
> include/linker_lists.h:48:9: note: in expansion of macro ‘ll_emit_type_info’
> 48 | ll_emit_type_info(_list, _type);
> \
> | ^~~~~~~~~~~~~~~~~
> include/linker_lists.h:297:9: note: in expansion of macro ‘ll_emit_start_symbol’
> 297 | ll_emit_start_symbol(_list, _type);
> \
> | ^~~~~~~~~~~~~~~~~~~~
>
> See below
I don't see that, and I did use sandbox as one of the targets I
built. Running the script on the sandbox u-boot ELF file, I get
List Start End Size Align Count
acpi_writer 0x00449440 0x00449580 32 8 10
bootdev_hunter 0x00449580 0x00449658 24 8 9
cmd 0x00449660 0x0044cb50 56 8 242
[...]
usb_driver_entry 0x0045a9a0 0x0045a9d0 16 8 3
ut 0x0045a9e0 0x00461ce0 32 8 920
ut_2_addrmap 0x0045a9e0 0x0045aa00 32 8 1
ut_2_bdinfo 0x0045aa00 0x0045aa80 32 8 4
ut_2_bloblist 0x0045aa80 0x0045ac40 32 8 14
[...]
ut_2_upl 0x00461c60 0x00461ce0 32 8 4
w1_driver_entry 0x00461ce0 0x00461ce0 16 8 0
i.e. ut is both shown as the whole list with 920 entries, and each
sublist is also shown, exactly as I wanted it to appear.
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -23,7 +24,45 @@
>> +#define ll_emit_type_info(_list, _type) \
>> + __asm__( \
>> + ".pushsection "ll_info_section_name(_list)',\'aw\'\n' \
>> + ".type "ll_size_symbol_name(_list)", STT_OBJECT\n" \
>> + ".size "ll_size_symbol_name(_list)", %c0\n" \
>> + ".type "ll_align_symbol_name(_list)", STT_OBJECT\n" \
>> + ".size "ll_align_symbol_name(_list)", %c1\n" \
>> + ll_size_symbol_name(_list)':\n' \
>> + ll_align_symbol_name(_list)':\n' \
>> + '.popsection\n' \
>> + : : 'i'(sizeof(_type)), 'i'(__alignof__(_type)))
>
> This is extended asm (it has operand constraints), so GCC requires it
> to be inside a function.
Not exactly. My 'info gcc' has this to say:
Similarly to basic ‘asm’, extended ‘asm’ statements may be used both
inside a C function or at file scope ("top-level"), where you can use
this technique to emit assembler directives, define assembly language
macros that can be invoked elsewhere in the file, or write entire
functions in assembly language. Extended ‘asm’ statements outside of
functions may not use any qualifiers, may not specify clobbers, may
not use ‘%’, ‘+’ or ‘&’ modifiers in constraints and can only use
constraints which don't allow using any register.
and since the only constraints I use are those that provide an immediate
to the asm, that should be ok (and WorksForMe).
I'm not sure how it has happened, but in your reply, some of the double
quotes have turned into single quotes (e.g. "i" has become 'i', ":\n"
has become ':\n'). Both here and further down. I hope you haven't tried
to compile the code in that form.
> ll_start_decl()/ll_end_decl() pull this into
> ll_emit_start_symbol/ll_emit_end_symbol at file scope - see
> SUITE_DECL() in test/cmd_ut.c
>
> One way out is to drop the operands and have the C side emit a
> zero-initialised marker object whose array dimensions encode
> sizeof/__alignof__ - e.g. a static struct in a dedicated section whose
> two members are sized sizeof(_type) and __alignof__(_type). That costs
> a few bytes per list per TU but keeps the trick working at file scope.
>
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -23,7 +24,45 @@
>> +#define ll_emit_start_symbol(_list, _type) \
>> + ll_emit_type_info(_list, _type); \
>> + __asm__( \
>> + ".pushsection "ll_start_section_name(_list)',\'aw\'\n' \
>> + ".type "__stringify(ll_start_symbol_name(_list))", STT_OBJECT\n" \
>> + ".size "__stringify(ll_start_symbol_name(_list))", 0\n" \
>> + __stringify(ll_start_symbol_name(_list))':\n' \
>> + '.popsection\n' \
>> + )
>
> These multi-statement macros are not wrapped, so they only work in
> contexts that accept two declarations/statements separated by ';'.
> ll_start_decl() then chains another declaration after them, leaving a
> stray ';' at file scope
No. The definition of ll_emit_start_symbol() does not end with a
semi-colon, the user supplies that, so that it reads e.g.
#define ll_start_decl(_sym, _type, _list) \
ll_emit_start_symbol(_list, _type); \
static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
__section(ll_start_section_name(_list))
and the user of ll_start_decl() in turn supplies a ; at the invocation
site.
There's no stray ; anywhere that I can see.
- accepted as a GCC extension but rejected
> under -Wpedantic. Please either fold the two asm blocks into one (a
> single .pushsection ... .popsection can contain all the
> .type/.size/label directives), or wrap them in a way that gives a
> single declaration/statement. The latter is awkward at file scope,
> which is another argument for the single-asm approach.
Sorry, I don't see the purpose, as I still need at least one statement
beyond the existing symbol definition,
and by defining the statement-generating macros in a way that they never
include a trailing semi-colon, they can freely include other such
macros. And I don't want to duplicate the type_info macro, that's why
it's split off in the first place.
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -23,7 +24,45 @@
>> +#define ll_info_section_name(_list) '__u_boot_list_'#_list'_0'
>
> Worth mentioning in the commit message that this is matched by the
> existing KEEP(*(SORT(__u_boot_list*))) globs in all the linker
> scripts, so the new _0 sections end up in the linker_list region of
> the final image. Since each section is zero bytes that does not affect
> binary size, but it does mean the metadata is reachable from the ELF
> symtab without changing any board's linker script - which is exactly
> what you say you wanted.
Yes, and I don't really need those sections to include the #_list part,
I could just create a single __u_boot_list___metadata section. I used
the above mostly so that they list metadata symbols for a given list end
up immediately preceding the items belonging to that list in an 'nm -n'
dump.
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -23,7 +24,45 @@
>> +#define ll_info_section_name(_list) '__u_boot_list_'#_list'_0'
>> +#define ll_size_symbol_name(_list) '_u_boot_list_'#_list'_0_item_size'
>> +#define ll_align_symbol_name(_list) '_u_boot_list_'#_list'_0_item_align'
>
> The size/align symbols are emitted as local labels, so every TU that
> touches a given list contributes its own local copy.
That is deliberate.
> That is fine for the parser in patch 9, but it relies on strip/objcopy
> not throwing away local symbols on the way to the final image.
No, it does not.
> A note about this - or about pointing the script at u-boot (the
> unstripped ELF) rather than u-boot.bin - would help anyone trying this
> themselves.
The script cannot be used on u-boot.bin at all, that has no symbol
information and is not an ELF file. The whole point is that I emit a lot
of symbols and metadata associated to those that _is_ thrown away by
objcopy, so u-boot.bin remains unchanged.
>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>> @@ -128,6 +167,7 @@
>> #define ll_entry_start(_type, _list) \
>> ({ \
>> + ll_emit_start_symbol(_list, _type); \
>> static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \
>> __section(ll_start_section_name(_list)); \
>
> Just to check: is there any reason ll_entry_start() emits the metadata
> at every call site rather than only where the start/end markers are
> first defined?
Yes.
> Within a given TU every call expands to the same
> .size/.type for the same symbol, which the assembler tolerates but is
> wasted work.
No, because this is part of the sanity checking I want to do. If you
ever use ll_something(ctrl, struct foo) and also ll_something(ctrl,
struct bar), I'd like to catch at build time that the 'ctrl' list is
used with two different types.
Sure, the sizes could (and often will) match, so it's not foolproof, but
it can catch some cases. I'm trying to come up with some way to make
this part even better, without adding anything that will cause
u-boot.bin to grow (I don't really care about the size of u-boot the ELF
file).
Rasmus
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking
2026-05-26 22:26 ` Rasmus Villemoes
@ 2026-05-26 22:41 ` Rasmus Villemoes
2026-05-27 4:09 ` Simon Glass
0 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-26 22:41 UTC (permalink / raw)
To: Simon Glass; +Cc: u-boot, Tom Rini
On Wed, May 27 2026, Rasmus Villemoes <ravi@prevas.dk> wrote:
> On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
>
>
>>> diff --git a/include/linker_lists.h b/include/linker_lists.h
>>> @@ -23,7 +24,45 @@
>>> +#define ll_emit_type_info(_list, _type) \
>>> + __asm__( \
>>> + ".pushsection "ll_info_section_name(_list)',\'aw\'\n' \
>>> + ".type "ll_size_symbol_name(_list)", STT_OBJECT\n" \
>>> + ".size "ll_size_symbol_name(_list)", %c0\n" \
>>> + ".type "ll_align_symbol_name(_list)", STT_OBJECT\n" \
>>> + ".size "ll_align_symbol_name(_list)", %c1\n" \
>>> + ll_size_symbol_name(_list)':\n' \
>>> + ll_align_symbol_name(_list)':\n' \
>>> + '.popsection\n' \
>>> + : : 'i'(sizeof(_type)), 'i'(__alignof__(_type)))
>>
>> This is extended asm (it has operand constraints), so GCC requires it
>> to be inside a function.
>
> Not exactly. My 'info gcc' has this to say:
>
> Similarly to basic ‘asm’, extended ‘asm’ statements may be used both
> inside a C function or at file scope ("top-level"), where you can use
> this technique to emit assembler directives, define assembly language
> macros that can be invoked elsewhere in the file, or write entire
> functions in assembly language. Extended ‘asm’ statements outside of
> functions may not use any qualifiers, may not specify clobbers, may
> not use ‘%’, ‘+’ or ‘&’ modifiers in constraints and can only use
> constraints which don't allow using any register.
>
> and since the only constraints I use are those that provide an immediate
> to the asm, that should be ok (and WorksForMe).
Ah, that's actually new in gcc 15 (I'm using gcc
16). https://gcc.gnu.org/gcc-15/changes.html says
Extended inline assembler statements can now be used with some
limitations outside of functions as well.
and explicitly calls out
"i" (sizeof (struct S))); /* It is possible to pass constants to toplevel asm. */
>> ll_start_decl()/ll_end_decl() pull this into
>> ll_emit_start_symbol/ll_emit_end_symbol at file scope - see
>> SUITE_DECL() in test/cmd_ut.c
>>
>> One way out is to drop the operands and have the C side emit a
>> zero-initialised marker object whose array dimensions encode
>> sizeof/__alignof__ - e.g. a static struct in a dedicated section whose
>> two members are sized sizeof(_type) and __alignof__(_type). That costs
>> a few bytes per list per TU but keeps the trick working at file scope.
Yes, but this is the kind of growth that I wanted to avoid. And if I put
those marker objects in a section of their own, I'll have to modify each
and every linker script to preserve that to the u-boot binary, but
ensure that the objcopy step throws it away.
I'll think about this some more.
Rasmus
^ permalink raw reply [flat|nested] 32+ messages in thread* Re: [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking
2026-05-26 22:41 ` Rasmus Villemoes
@ 2026-05-27 4:09 ` Simon Glass
0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-27 4:09 UTC (permalink / raw)
To: Rasmus Villemoes; +Cc: u-boot, Tom Rini
Hi Rasmus,
On Tue, 26 May 2026 at 16:41, Rasmus Villemoes <ravi@prevas.dk> wrote:
>
> On Wed, May 27 2026, Rasmus Villemoes <ravi@prevas.dk> wrote:
>
> > On Mon, May 25 2026, Simon Glass <sjg@chromium.org> wrote:
> >
> >
> >>> diff --git a/include/linker_lists.h b/include/linker_lists.h
> >>> @@ -23,7 +24,45 @@
> >>> +#define ll_emit_type_info(_list, _type) \
> >>> + __asm__( \
> >>> + ".pushsection "ll_info_section_name(_list)',\'aw\'\n' \
> >>> + ".type "ll_size_symbol_name(_list)", STT_OBJECT\n" \
> >>> + ".size "ll_size_symbol_name(_list)", %c0\n" \
> >>> + ".type "ll_align_symbol_name(_list)", STT_OBJECT\n" \
> >>> + ".size "ll_align_symbol_name(_list)", %c1\n" \
> >>> + ll_size_symbol_name(_list)':\n' \
> >>> + ll_align_symbol_name(_list)':\n' \
> >>> + '.popsection\n' \
> >>> + : : 'i'(sizeof(_type)), 'i'(__alignof__(_type)))
> >>
> >> This is extended asm (it has operand constraints), so GCC requires it
> >> to be inside a function.
> >
> > Not exactly. My 'info gcc' has this to say:
> >
> > Similarly to basic ‘asm’, extended ‘asm’ statements may be used both
> > inside a C function or at file scope ("top-level"), where you can use
> > this technique to emit assembler directives, define assembly language
> > macros that can be invoked elsewhere in the file, or write entire
> > functions in assembly language. Extended ‘asm’ statements outside of
> > functions may not use any qualifiers, may not specify clobbers, may
> > not use ‘%’, ‘+’ or ‘&’ modifiers in constraints and can only use
> > constraints which don't allow using any register.
> >
> > and since the only constraints I use are those that provide an immediate
> > to the asm, that should be ok (and WorksForMe).
>
> Ah, that's actually new in gcc 15 (I'm using gcc
> 16). https://gcc.gnu.org/gcc-15/changes.html says
>
> Extended inline assembler statements can now be used with some
> limitations outside of functions as well.
>
> and explicitly calls out
>
> "i" (sizeof (struct S))); /* It is possible to pass constants to toplevel asm. */
Oh OK, actually I am still using gcc 14 locally. It didn't occur to me
that something like this would change in the toolchain! Presumably
clang already has this ability?
>
> >> ll_start_decl()/ll_end_decl() pull this into
> >> ll_emit_start_symbol/ll_emit_end_symbol at file scope - see
> >> SUITE_DECL() in test/cmd_ut.c
> >>
> >> One way out is to drop the operands and have the C side emit a
> >> zero-initialised marker object whose array dimensions encode
> >> sizeof/__alignof__ - e.g. a static struct in a dedicated section whose
> >> two members are sized sizeof(_type) and __alignof__(_type). That costs
> >> a few bytes per list per TU but keeps the trick working at file scope.
>
> Yes, but this is the kind of growth that I wanted to avoid. And if I put
> those marker objects in a section of their own, I'll have to modify each
> and every linker script to preserve that to the u-boot binary, but
> ensure that the objcopy step throws it away.
>
> I'll think about this some more.
Also check my RFC which attempts to do this checking with no changes
to linker lists. It certainly found problems but I suspect your
approach is more powerful and will find more?
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread
* [RFC PATCH 9/9] tools: add linker-lists.py parser/checker script
2026-05-22 21:27 [RFC PATCH 0/9] linker list sanity checking Rasmus Villemoes
` (7 preceding siblings ...)
2026-05-22 21:27 ` [RFC PATCH 8/9] linker_lists.h: emit lots of meta-data for debugging and sanity checking Rasmus Villemoes
@ 2026-05-22 21:27 ` Rasmus Villemoes
2026-05-25 15:04 ` Simon Glass
8 siblings, 1 reply; 32+ messages in thread
From: Rasmus Villemoes @ 2026-05-22 21:27 UTC (permalink / raw)
To: u-boot; +Cc: Simon Glass, Tom Rini, Rasmus Villemoes
Add a python script which will make use of the special symbols emitted
by the linker list macros, and perform various sanity checks. By
default, it ends with printing a list of all the defined linker lists,
including their start/end addresses, the size and aligment of
individual items and the number of items.
With --check, it only does the sanity checking and its exit code
reflects whether any problems were found. That is eventually intended
to be done as part of the build.
With --dump, it not only prints the lists and their overall
properties, but also the names/addresses of each item belong to the
list.
Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
---
tools/linker-lists.py | 234 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 234 insertions(+)
create mode 100755 tools/linker-lists.py
diff --git a/tools/linker-lists.py b/tools/linker-lists.py
new file mode 100755
index 00000000000..419879ee31a
--- /dev/null
+++ b/tools/linker-lists.py
@@ -0,0 +1,234 @@
+#!/usr/bin/python3
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+import sys
+from argparse import ArgumentParser
+import subprocess
+
+# Parse the output of
+#
+# readelf --wide --symbols u-boot
+#
+# or
+#
+# nm --print-size u-boot
+#
+# do sanity checks, and optionally print information on all the
+# defined lists.
+
+bad_lists = set()
+def warn(list_name, msg):
+ print(msg, file=sys.stderr)
+ bad_lists.add(list_name)
+
+class unique_dict(dict):
+ def __init__(self, name, format_spec, *arg, **kw):
+ super(unique_dict, self).__init__(*arg, **kw)
+ self.name = name
+ self.format_spec = format_spec
+
+ def __setitem__(self, key, value):
+ if key in self:
+ old = self[key]
+ if value != old:
+ warn(key,
+ f"Inconsistent {self.name} for list '{key}': Old value {self.format_spec}, new value {self.format_spec}" %
+ (old, value))
+ return
+ super(unique_dict, self).__setitem__(key, value)
+
+# <list name> -> <value>
+item_size = unique_dict("size", "%d")
+item_alignment = unique_dict("alignment", "%d")
+start_address = unique_dict("start address", "0x%08x")
+end_address = unique_dict("end address", "0x%08x")
+
+# <list name> -> list of (name, address, size) triples
+entries = dict()
+
+def handle_symbol(symbol, address, size):
+ if not symbol.startswith("_u_boot_list_"):
+ return
+
+ symbol = symbol[13:]
+ if symbol.endswith("_1_start"):
+ assert(size == 0)
+ start_address[symbol[0:-8]] = address
+ return
+
+ if symbol.endswith("_3_end"):
+ assert(size == 0)
+ end_address[symbol[0:-6]] = address
+ return
+
+ if symbol.endswith("_0_item_align"):
+ item_alignment[symbol[0:-13]] = size
+ return
+
+ if symbol.endswith("_0_item_size"):
+ item_size[symbol[0:-12]] = size
+ return
+
+ # Deal with lists/sublists. ut_2_bootm_2_bootm_test_silent
+ # - An entry called "bootm_2_bootm_test_silent" in the outer "ut" list, and
+ # - An entry called "bootm_test_silent" in the "ut_2_bootm" list.
+
+ atoms = symbol.split("_2_")
+ if len(atoms) < 2:
+ return
+
+ for i in range(1, len(atoms)):
+ list_name = "_2_".join(atoms[0:i])
+ entry_name = "_2_".join(atoms[i:])
+ if list_name not in entries:
+ entries[list_name] = []
+ entries[list_name].append((entry_name, address, size))
+
+def parse_readelf(line):
+ # Fields are
+ #
+ # Num: Value Size Type Bind Vis Ndx Name
+ #
+ # where Value (i.e. address) is in hex and Size is in
+ # decimal. There are lines (such as that header line) that we just
+ # need to ignore.
+ fields = line.split()
+ if len(fields) != 8:
+ return
+
+ (_, address, size, _, _, _, _, symbol) = fields
+
+ address = int(address, 16)
+ size = int(size, 10)
+
+ handle_symbol(symbol, address, size)
+
+def parse_nm(line):
+ # Fields are
+ #
+ # Address [Size] Type Name
+ #
+ # but [Size] is not present when it is 0. Both Address and Size
+ # are in hex.
+ fields = line.split()
+ if len(fields) == 4:
+ (address, size, _, symbol) = fields
+ size = int(size, 16)
+ elif len(fields) == 3:
+ (address, _, symbol) = fields
+ size = 0
+ else:
+ return
+
+ address = int(address, 16)
+
+ handle_symbol(symbol, address, size)
+
+
+ap = ArgumentParser(description='Linker lists sanity checker')
+
+ap.add_argument('--parser', '-p', default='nm', choices=['nm', 'readelf'],
+ help='Program to use to parse the ELF file (nm or readelf)')
+ap.add_argument('--check', '-c', action='store_true',
+ help='Only do sanity checks and exit non-zero if any problems are found')
+ap.add_argument('--dump', '-d', action='store_true',
+ help='Print all individual list entries')
+
+ap.add_argument('elf_file', metavar='ELF_FILE', nargs='?', default="u-boot", help='ELF file to parse (default u-boot)')
+
+args = ap.parse_args()
+
+if args.parser == 'nm':
+ parser = parse_nm
+ cmd = ['nm', '--print-size', args.elf_file]
+else:
+ parser = parse_readelf
+ cmd = ['readelf', '--symbols', '--wide', args.elf_file]
+
+subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
+
+for line in subp.stdout:
+ if "_u_boot_list_" not in line:
+ continue
+ parser(line)
+
+# These should all be the same, except perhaps that there might be lists without entries.
+list_names = set(item_size.keys())
+list_names.update(item_alignment.keys())
+list_names.update(start_address.keys())
+list_names.update(end_address.keys())
+list_names.update(entries.keys())
+
+list_names = list(list_names)
+list_names.sort(key=lambda x: (start_address.get(x, 0), x))
+
+for name in list_names:
+ # There really should be item_size and item_alignment values for
+ # all lists. Otherwise, we've emitted list entries to a list that
+ # is never referred to via the start/end macros.
+ size = item_size.get(name)
+ align = item_alignment.get(name)
+ if size is None:
+ warn(name, f"No known entry size for list '{name}'")
+ # Let the below sanity checks pass.
+ size = 1
+ if align is None:
+ warn(name, f"No known entry alignment for list '{name}'")
+ # Let the below sanity checks pass.
+ align = 1
+
+ if size % align != 0:
+ warn(name, f"Item size {size} for list '{name}' is not a multiple of the alignment {align}")
+
+ start = start_address.get(name)
+ end = end_address.get(name)
+
+ if start is None:
+ warn(name, f"No known start address for list '{name}'")
+ elif start % align != 0:
+ warn(name, f"Start address 0x{start:08x} for list '{name}' is not {align}-byte aligned")
+
+ if end is None:
+ warn(name, f"No known end address for list '{name}'")
+ elif end % align != 0:
+ warn(name, f"End address 0x{end:08x} for list '{name}' is not {align}-byte aligned")
+
+ if start is not None and end is not None and (end - start) % size != 0:
+ warn(name, f"Difference {end - start} between start 0x{start:08x} and end 0x{end:08x} addresses for list '{name}' is not a multiple of the item size {size}")
+
+ for (symbol, address, entry_size) in entries.get(name, []):
+ if start is not None and address < start:
+ warn(name, f"Entry {symbol} in list {name} has address 0x{address:08x} before start address 0x{start:08x}")
+ if end is not None and address > end:
+ warn(name, f"Entry {symbol} in list {name} has address 0x{address:08x} after end address 0x{end:08x}")
+ if entry_size % size != 0:
+ warn(name, f"Size {entry_size} of entry {symbol} in list {name} is not a multiple item size {size}")
+ if address % align != 0:
+ warn(name, f"Address 0x{address:08x} of entry {symbol} in list {name} is not {align}-byte aligned")
+
+if args.check:
+ if len(bad_lists) == 0:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+
+print(f"{'List':36s}\t{'Start':10s}\t{'End':10s}\tSize\tAlign\tCount")
+
+for name in list_names:
+ size = item_size.get(name, 1)
+ align = item_alignment.get(name, 1)
+ start = start_address.get(name, 0)
+ end = end_address.get(name, 0)
+ count = (end - start) // size
+ if name in bad_lists:
+ bang = "\t!!!"
+ else:
+ bang = ""
+
+ print(f"{name:36s}\t0x{start:08x}\t0x{end:08x}\t{size}\t{align}\t{count}{bang}")
+ if not args.dump:
+ continue
+
+ for (symbol, address, entry_size) in entries.get(name, []):
+ print(f" {symbol:32s}\t0x{address:08x}\t{'':10s}\t{entry_size}\t\t{entry_size // size}")
--
2.54.0
^ permalink raw reply related [flat|nested] 32+ messages in thread* Re: [RFC PATCH 9/9] tools: add linker-lists.py parser/checker script
2026-05-22 21:27 ` [RFC PATCH 9/9] tools: add linker-lists.py parser/checker script Rasmus Villemoes
@ 2026-05-25 15:04 ` Simon Glass
0 siblings, 0 replies; 32+ messages in thread
From: Simon Glass @ 2026-05-25 15:04 UTC (permalink / raw)
To: ravi; +Cc: u-boot, Simon Glass, Tom Rini
Hi Rasmus,
On 2026-05-22T21:27:48, Rasmus Villemoes <ravi@prevas.dk> wrote:
> tools: add linker-lists.py parser/checker script
>
> Add a python script which will make use of the special symbols emitted
> by the linker list macros, and perform various sanity checks. By
> default, it ends with printing a list of all the defined linker lists,
> including their start/end addresses, the size and aligment of
> individual items and the number of items.
>
> With --check, it only does the sanity checking and its exit code
> reflects whether any problems were found. That is eventually intended
> to be done as part of the build.
>
> With --dump, it not only prints the lists and their overall
> properties, but also the names/addresses of each item belong to the
> list.
>
> Signed-off-by: Rasmus Villemoes <ravi@prevas.dk>
>
> tools/linker-lists.py | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 234 insertions(+)
Perhaps check-linker-lists.py ? BTW I did write a checker script which
works just with the existing linker lists, but I don't think it is as
powerful as the mechanism you have here. I'll send it as an RFC just
for comparison. That is how I found the alignment problems.
Please use single quotes by default for strings (unless you need a
single quote in the string, iwc the outer would should be double
quotes)
> diff --git a/tools/linker-lists.py b/tools/linker-lists.py
> new file mode 100755
> index 00000000000..419879ee31a
> --- /dev/null
> +++ b/tools/linker-lists.py
> @@ -0,0 +1,234 @@
> +#!/usr/bin/python3
> +# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +
> +import sys
> +from argparse import ArgumentParser
> +import subprocess
Please switch to '#!/usr/bin/env python3' as the absolute path is not
portable. Also please add a short module docstring
> diff --git a/tools/linker-lists.py b/tools/linker-lists.py
> @@ -0,0 +1,234 @@
> +class unique_dict(dict):
> + def __init__(self, name, format_spec, *arg, **kw):
> + super(unique_dict, self).__init__(*arg, **kw)
Can this just be super().__init__(...) ?
> + self.name = name
> + self.format_spec = format_spec
> +
> + def __setitem__(self, key, value):
> + if key in self:
> + old = self[key]
> + if value != old:
> + warn(key,
> + f"Inconsistent {self.name} for list '{key}': Old value {self.format_spec}, new value {self.format_spec}" %
> + (old, value))
> + return
> + super(unique_dict, self).__setitem__(key, value)
Mixing an f-string with trailing %-formatting is hard to follow - how
about something like::
warn(key, f"Inconsistent {self.name} for list '{key}': "
f"Old value {old:{self.format_spec}}, new value
{value:{self.format_spec}}")
with format_spec stored as 'd' / '#010x' rather than C-style
> diff --git a/tools/linker-lists.py b/tools/linker-lists.py
> @@ -0,0 +1,234 @@
> +def handle_symbol(symbol, address, size):
> + if not symbol.startswith('_u_boot_list_'):
> + return
> +
> + symbol = symbol[13:]
> + if symbol.endswith('_1_start'):
> + assert(size == 0)
> + start_address[symbol[0:-8]] = address
> + return
> +
> + if symbol.endswith('_3_end'):
> + assert(size == 0)
> + end_address[symbol[0:-6]] = address
> + return
> +
> + if symbol.endswith('_0_item_align'):
> + item_alignment[symbol[0:-13]] = size
> + return
> +
> + if symbol.endswith('_0_item_size'):
> + item_size[symbol[0:-12]] = size
> + return
The magic slice offsets ([13:] etc.) are fiddly to verify by eye and
easy to break if any suffix changes. Please use
str.removeprefix()/str.removesuffix() - they are self-documenting and
the offsets disappear.
Also, the two assert(size == 0) calls are the wrong tool - if the ELF
ever contains a malformed start/end marker the script crashes rather
than reports. Since the whole point is sanity checking, better to call
warn() (and carry on) instead?
> diff --git a/tools/linker-lists.py b/tools/linker-lists.py
> @@ -0,0 +1,234 @@
> +subp = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
> +
> +for line in subp.stdout:
> + if '_u_boot_list_' not in line:
> + continue
> + parser(line)
There is no subp.wait() and no return-code check. If the ELF is
missing, or nm/readelf is not installed, the tool writes its complaint
to stderr and silently reports zero lists - and with --check still
exits 0, which is exactly the failure mode this is meant to catch in
CI. Please check subp.returncode after the loop and fail with a
message. Using 'with subprocess.Popen(...) as subp:' also ensures the
pipe is cleaned up.
> diff --git a/tools/linker-lists.py b/tools/linker-lists.py
> @@ -0,0 +1,234 @@
> +ap = ArgumentParser(description='Linker lists sanity checker')
> +
> +ap.add_argument('--parser', '-p', default='nm', choices=['nm', 'readelf'],
> + help='Program to use to parse the ELF file (nm or readelf)')
The whole body of the script runs at module scope. Please wrap it in a
main() function with the standard
if __name__ == '__main__':
sys.exit(main())
guard. That matches the other tools/ scripts and lets the parsing
helpers be imported by a future test without side effects.
> Add a python script which will make use of the special symbols emitted
> by the linker list macros, and perform various sanity checks. By
> default, it ends with printing a list of all the defined linker lists,
> including their start/end addresses, the size and aligment of
> individual items and the number of items.
Typos: 'alignment', and later 'each item belong to the list' should
read 'belonging to the list'.
Regards,
Simon
^ permalink raw reply [flat|nested] 32+ messages in thread