Consider the following simple example, "main.cpp":
Code: Select all
#include <Uefi.h>
#include <Library/UefiLib.h>
struct GlobalType {
int var;
GlobalType () { var=1; }
};
GlobalType foo, bar, baz;
EFI_STATUS EFIAPI efi_main( IN EFI_HANDLE /*image_handle*/, IN EFI_SYSTEM_TABLE* sys_table ) {
sys_table->ConOut->OutputString( sys_table->ConOut, (CHAR16*)L"Var is: \"" );
CHAR16 str[3+1] = { (CHAR16)(foo.var+'0'), (CHAR16)(bar.var+'0'), (CHAR16)(baz.var+'0'), '\0' };
sys_table->ConOut->OutputString( sys_table->ConOut, str );
sys_table->ConOut->OutputString( sys_table->ConOut, (CHAR16*)L"\"" );
while (1) asm("hlt");
return 0;
}
When you boot with the resulting "bootx64.efi", you'll get a screen that cheerfully says#Path to EDK II (https://github.com/tianocore/edk2) root "edk2/" directory, for UEFI headers
UEFI_ROOT=/path/to/edk2/
clang -I${UEFI_ROOT}MdePkg/Include/ -I${UEFI_ROOT}MdePkg/Include/X64 -ffreestanding -fshort-wchar -target x86_64-pc-win32-coff -c main.cpp
lld-link -subsystem:efi_application -dll -entry:efi_main -nodefaultlib -filealign:16 -out:bootx64.efi main.o
I.e., the global constructors for `foo`, `bar`, and `baz`did not run. That's not particularly surprising, since we didn't call them. I want to know how.Var is: "000"
The wiki has a page Calling Global Constructors which is pretty out-of-date, and GCC-centric anyway. I also found a blog post and more practically a previous thread where it was explained that one should walk through symbols `__init_array_start` to `__init_array_end`, but all of this seems to be for "-target i386-elf", which is not usable for a UEFI application. At any rate, I tried various things in these directions without really knowing what I was doing, and either failed to get it to link or it didn't work. How is it supposed to work?