Приложение оболочки EDK2, использующее переменные аргументы, построенные с помощью GCC, вызывает ошибку страницы при запуске

#c #gcc #clang #uefi #edk2

Вопрос:

У меня возникли проблемы с использованием переменных аргументов в EDK2 (приложение оболочки x64) при сборке под хостом Linux с gcc. Программа строится, но при выполнении она вызовет ошибку страницы в момент выполнения функции VA_ARG ().

Тот же код, созданный под хостом Windows с VS2015, работает без проблем.

Это, похоже, связано с ошибкой GCC 50818, но я не могу найти решения.

 #include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/PrintLib.h>
#include <Library/ShellCEntryLib.h>

VOID PrintInts(UINTN n, ...)
{
    VA_LIST vl;
    VA_START(vl, n);
    Print(L"Printing integers:");
    for (UINTN i=0; i<n; i  ) {
        UINTN val = 0;
        val = VA_ARG(vl, UINTN);
        Print(L" [%d]", val);
  }
  VA_END(vl);
  Print(L"n");
}

INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
{
    UINTN a = 3;
    UINTN b = 10;
    UINTN c = 9;
    PrintInts(3, a, b, c);
    return 0;
}
 

Ответ №1:

Я нашел исправление, которое заключается в определении функции с EFIAPI помощью тега, и это устраняет проблему, т. Е.

 VOID EFIAPI PrintInts(UINTN n, ...)
 

По этой ссылке:

При создании 32-разрядного приложения UEFI EFIAPI пуст; GCC скомпилирует функцию «efi_main», используя стандартное соглашение о вызовах C. При создании 64-разрядного приложения UEFI EFIAPI расширяется до «__атрибут__((ms_abi))», и GCC скомпилирует функцию «efi_main», используя соглашение о вызовах x64 корпорации Майкрософт, как указано в UEFI. Только функции, которые будут вызываться непосредственно из UEFI (включая основные, но также обратные вызовы), должны использовать соглашение о вызовах UEFI.

Кроме того, это только кажется проблемой с GCC, как если бы я использовал CLANG, мне не нужно указывать EFIAPI.