diff options
| author | Tom Rini <[email protected]> | 2026-04-14 11:04:04 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-04-14 11:04:04 -0600 |
| commit | 5a998ab00758a0cc757d39335d515694c60e7062 (patch) | |
| tree | 46ab0e1812850ffaca27d24f6dc551636e5d48c4 /include | |
| parent | 564e180d701f3946e6adc7895f2524728b985f03 (diff) | |
| parent | a6672a4804debd9de4f7bcc1d2f2a07ff30e1eed (diff) | |
Merge patch series "A few linker-list fixes"
Simon Glass <[email protected]> says:
This series includes two patches to fix alignment problems with linker
lists. In certain circumstances these can cause the drivers list to be
non-contiguous, causing crashes, hangs, etc.
Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'include')
| -rw-r--r-- | include/linker_lists.h | 25 |
1 files changed, 22 insertions, 3 deletions
diff --git a/include/linker_lists.h b/include/linker_lists.h index 78ba937c8c3..4425fcb6785 100644 --- a/include/linker_lists.h +++ b/include/linker_lists.h @@ -145,6 +145,20 @@ * Since this macro defines an array end symbol, its leftmost index * must be 2 and its rightmost index must be 3. * + * The end symbol uses __aligned(1) to ensure it is placed immediately after + * the last entry without any padding. This is critical for ll_entry_count() + * to work correctly. + * + * If the end marker had a higher alignment (e.g., 4 or 32 bytes), the linker + * might insert padding between the last entry and the end marker to satisfy + * alignment requirements of the following section. This would cause pointer + * subtraction (end - start) to produce incorrect results because the compiler + * optimizes pointer division using magic-number multiplication, which only + * works correctly when the byte span is an exact multiple of the struct size. + * + * With __aligned(1), the end marker is placed at exactly (start + n * sizeof) + * where n is the number of entries, ensuring correct pointer arithmetic. + * * Example: * * :: @@ -153,7 +167,7 @@ */ #define ll_entry_end(_type, _list) \ ({ \ - static char end[0] __aligned(4) __attribute__((unused)) \ + static char end[0] __aligned(1) __attribute__((unused)) \ __section("__u_boot_list_2_"#_list"_3"); \ _type * tmp = (_type *)&end; \ asm("":"+r"(tmp)); \ @@ -239,8 +253,12 @@ static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \ __maybe_unused __section("__u_boot_list_2_" #_list "_1") +/* + * ll_end_decl uses __aligned(1) to avoid padding before the end marker. + * See the comment for ll_entry_end() for a full explanation. + */ #define ll_end_decl(_sym, _type, _list) \ - static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \ + static _type _sym[0] __aligned(1) \ __maybe_unused __section("__u_boot_list_2_" #_list "_3") /** @@ -266,7 +284,8 @@ */ #define ll_entry_get(_type, _name, _list) \ ({ \ - extern _type _u_boot_list_2_##_list##_2_##_name; \ + extern _type _u_boot_list_2_##_list##_2_##_name \ + __aligned(4); \ _type *_ll_result = \ &_u_boot_list_2_##_list##_2_##_name; \ _ll_result; \ |
