DEVICE_DEFINE(): properly align struct device instances

The DEVICE_DEFINE() macro creates instances of struct device that are
gathered into a contiguous list by the linker. However, some assemblers
pad sections to the next 16-byte boundary or so by default, screwing up
the list walk in z_sys_device_do_config_level(). This is especially
true for 64-bit compilation where sizeof(struct device) isn't a
multiple of 16.

Enforcing an alignment at the linker level would solve this issue when
instances of struct device are gathered from different object files.
However it doesn't solve it when multiple instances are created within
the same object file where the first instance still has a gap with the
next instance, as the assembler does add padding upon section switch
even though the object file ends up with a single section with both
instances. In that case the linker would get rid of the trailing padding
only, leaving the inner gaps between instances in place.

The actual fix is to provide an explicit alignment attribute to the
section for every instances, using __alignof(struct device) which is
the alignment expected by the compiler for that structure.

This also means that the x86_64 workaround in the struct device
definition may go as the "edge case" it refers to is now properly
handled.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
Nicolas Pitre 2019-05-17 15:28:13 -04:00 committed by Andrew Boie
commit 7daa5451cf

View file

@ -108,7 +108,8 @@ extern "C" {
.config_info = (cfg_info) \
}; \
static struct device _CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
__attribute__((__section__(".init_" #level STRINGIFY(prio)), \
aligned(__alignof(struct device)))) = { \
.config = &_CONCAT(__config_, dev_name), \
.driver_api = api, \
.driver_data = data \
@ -165,7 +166,8 @@ extern "C" {
.config_info = (cfg_info) \
}; \
static struct device _CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
__attribute__((__section__(".init_" #level STRINGIFY(prio)), \
aligned(__alignof(struct device)))) = { \
.config = &_CONCAT(__config_, dev_name), \
.driver_api = api, \
.driver_data = data, \
@ -276,14 +278,6 @@ struct device {
struct device_config *config;
const void *driver_api;
void *driver_data;
#if defined(__x86_64) && __SIZEOF_POINTER__ == 4
/* The x32 ABI hits an edge case. This is a 12 byte struct,
* but the x86_64 linker will pack them only in units of 8
* bytes, leading to alignment problems when iterating over
* the link-time array.
*/
void *padding;
#endif
};
void z_sys_device_do_config_level(s32_t level);