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 <[email protected]>
---
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