
U-Boot makes extensive use of linker-generated lists to discover everything from drivers to commands at runtime. This clever mechanism allows developers to add new features with a single macro, and the linker automatically assembles them into a contiguous array. The C code can then iterate through this array by finding its start and end markers, which are also provided by the linker.
For this to work, there’s a critical assumption: the array of structs is perfectly contiguous, with each element having the exact same size. But what happens when the linker, in its quest for optimisation, breaks this assumption?
A Little Wrinkle
We have known for a while about a subtle issue where the linker, in certain cases, would insert a few bytes of padding between elements in these lists. This is usually done to align the next element to a more efficient memory boundary (like 8 or 16 bytes).
While this is often harmless, it breaks U-Boot’s C code, which expects to find the next element by simply adding a fixed size to the address of the current one. This unexpected padding can lead to misaligned memory access, corrupted data, and hard-to-debug crashes.
Here is an example of what this looks like in the symbol table. Notice the gap between virtio_fs
and virtio_fs_dir
is 0x80
bytes, while the expected size is 0x78
:
...
00000000011d0070 D _u_boot_list_2_driver_2_virtio_blk
00000000011d0160 D _u_boot_list_2_driver_2_virtio_fs
00000000011d01e0 D _u_boot_list_2_driver_2_virtio_fs_dir
...
This 8-byte padding (0x80 - 0x78
) is the source of the problem.
A Script to the Rescue
To catch these alignment problems automatically, we’ve developed a new Python script, check_list_alignment.py
, now in U-Boot Concept (merge).
The script works as follows:
- Runs
nm -n
on the finalu-boot
ELF file to get all symbols sorted by address. - Automatically discovers all the different linker lists in use (e.g.,
driver
,cmd
,uclass_driver
). - For each list, calculates the gap between every consecutive element.
- Determines the most common gap size, assuming this is the correct
sizeof(struct)
. - Flags any gap that doesn’t match this common size.
Now, if the linker introduces any unexpected padding, the build will fail immediately with a clear error message:
$ ./scripts/check_list_alignment.py -v u-boot
List Name # Symbols Struct Size (hex)
----------------- ----------- -----------------
...
driver 65 0x78
- Bad gap (0x80) before symbol: _u_boot_list_2_driver_2_virtio_fs_dir
...
FAILURE: Found 1 alignment problems
This simple check provides a powerful guarantee. It ensures the integrity of our linker lists, prevents a whole class of subtle bugs, and allows developers to continue using this powerful U-Boot feature with confidence.