]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: Fix alignment of long long inside structs on x86
authorJan Janssen <medhefgo@web.de>
Mon, 10 Apr 2023 09:43:56 +0000 (11:43 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Tue, 11 Apr 2023 16:09:18 +0000 (17:09 +0100)
On x86 EFI follows the windows ABI, which expects 8-byte aligned long
long. The x86 sysv ELF ABI expects them to be 8-byte aligned when used
alone, but 4-byte aligned when they appear inside of structs:

    struct S {
        int i;
        long long ll;
    };

    // _Static_assert(sizeof(struct S) == 12, "x86 sysv ABI");
    _Static_assert(sizeof(struct S) == 16, "EFI/MS ABI");

To get the behavior we need when building with sysv ELF ABI we need to
pass '-malign-double' to the compiler as done by EDK2.

This in turn will make ubsan unhappy as the stack may not be properly
aligned on entry, so we have to tell the compiler explicitly to re-align
the stack on entry to efi_main.

This fixes loading EFI drivers on x86 that were previously always
rejected as the EFI_LOADED_IMAGE_PROTOCOL had a wrong memory layout.

See also: https://github.com/rhboot/shim/pull/516

src/boot/efi/meson.build
src/boot/efi/util.h

index e6e7eed3bcac6a8f661c386428862e41cba3014d..67ce00838d4deaec604b63bf4555a0ef42c49a29 100644 (file)
@@ -213,15 +213,16 @@ efi_c_args_alt = [efi_c_args, '-DEFI_MACHINE_TYPE_NAME="' + efi_arch_alt + '"']
 efi_c_ld_args_primary = efi_c_ld_args
 efi_c_ld_args_alt = efi_c_ld_args
 
-efi_c_args_primary += {
+efi_arch_c_args = {
         'aarch64' : ['-mgeneral-regs-only'],
         'arm'     : ['-mgeneral-regs-only'],
         'x86_64'  : ['-march=x86-64', '-mno-red-zone', '-mgeneral-regs-only'],
-        'x86'     : ['-march=i686', '-mgeneral-regs-only'],
-}.get(host_machine.cpu_family(), [])
+        'x86'     : ['-march=i686', '-mgeneral-regs-only', '-malign-double'],
+}
+efi_c_args_primary += efi_arch_c_args.get(host_machine.cpu_family(), [])
 
 if efi_arch_alt == 'ia32'
-        efi_c_args_alt += ['-m32', '-march=i686', '-mgeneral-regs-only']
+        efi_c_args_alt += ['-m32', efi_arch_c_args['x86']]
         efi_c_ld_args_alt += '-m32'
 endif
 
index c321062996c5268658badcddbbdd684af4705253..9df7b4a2d4e833e1e252707c5c140027c93524b0 100644 (file)
@@ -168,10 +168,22 @@ void hexdump(const char16_t *prefix, const void *data, size_t size);
 #  define notify_debugger(i, w)
 #endif
 
+/* On x86 the compiler assumes a different incoming stack alignment than what we get.
+ * This will cause long long variables to be misaligned when building with
+ * '-mlong-double' (for correct struct layouts). Normally, the compiler realigns the
+ * stack itself on entry, but we have to do this ourselves here as the compiler does
+ * not know that this is our entry point. */
+#ifdef __i386__
+#  define _realign_stack_ __attribute__((force_align_arg_pointer))
+#else
+#  define _realign_stack_
+#endif
+
 #define DEFINE_EFI_MAIN_FUNCTION(func, identity, wait_for_debugger)                    \
         EFI_SYSTEM_TABLE *ST;                                                          \
         EFI_BOOT_SERVICES *BS;                                                         \
         EFI_RUNTIME_SERVICES *RT;                                                      \
+        _realign_stack_                                                                \
         EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table);  \
         EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table) { \
                 ST = system_table;                                                     \