image_pdfimage_print

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:

  1. Runs nm -n on the final u-boot ELF file to get all symbols sorted by address.
  2. Automatically discovers all the different linker lists in use (e.g., driver, cmd, uclass_driver).
  3. For each list, calculates the gap between every consecutive element.
  4. Determines the most common gap size, assuming this is the correct sizeof(struct).
  5. 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.

Author

  • Simon Glass is a primary author of U-Boot, with around 10K commits. He is maintainer of driver model and various other subsystems in U-Boot.

Leave a Reply

Your email address will not be published. Required fields are marked *