Page 1 of 1

Linking order of functions in VirtualBox + EFI32

Posted: Thu Oct 22, 2015 11:31 pm
by kzinti
I am working on a EFI loader. When I compile it in 64 bits mode (bootx64.efi), it works fine on qemu, virtualbox and my real computer. When I compile it in 32 bits mode (bootia32.efi), it only works if efi_main() is the first function in my (only) .cpp source file. If I put any function before it, it stops working. Here is the code:

Code: Select all

static EFI_SYSTEM_TABLE* efi;


extern "C" EFIAPI EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE* systemTable)
{
    efi = systemTable;

    printf("Kiznix EFI Application (efi_main) - %d bits.", sizeof(void*)*8);

    // Wait for a key press
    UINTN index;
    EFI_EVENT event = systemTable->ConIn->WaitForKey;
    systemTable->BootServices->WaitForEvent(1, &event, &index);

    return EFI_SUCCESS;
}



// TODO: If I move this function above efi_main(), it crashes on Virtual Box (32 bits).
// It works fine in 64 bits. No idea.
extern "C" int putchar(int i)
{
    CHAR16 c = (CHAR16)i;
    CHAR16 s[2] = { c, 0 };

    SIMPLE_TEXT_OUTPUT_INTERFACE* out = efi->ConOut;
    out->OutputString(out, s);

    return c;
}
I am using the mingw toolchain (x86_64-w64-mingw32-gcc) to compile, link as a shared library with "-nostdlib -e efi_main" and use "objcopy --target=efi-app-ia32" to properly set the PE header on the resulting executable.

Again, this works fine in 64 bits on 3 platforms and the order of the functions doesn't matter. I only have the issue in 32 bits in virtualbox. I do not have any other system/emulator that will even attempt to boot bootia32.efi.

Google returns nothing.

Any idea?

Re: Linking order of functions in VirtualBox + EFI32

Posted: Thu Oct 22, 2015 11:32 pm
by kzinti
Forgot to add: I have printf() compiled in a static library and it basically calls putchar() for output.

I also verified that when it does work, efi_main() is right at the start of the .text section. I guess I can just put efi_main() in its own section and make sure it's first... Still this is weird isn't it?

Re: Linking order of functions in VirtualBox + EFI32

Posted: Thu Oct 22, 2015 11:41 pm
by kzinti
Oh I found this warning:
/usr/bin/i686-w64-mingw32-ld: warning: cannot find entry symbol efi_main; defaulting to 0000000062941000

That's the problem. Why is it not finding efi_main in 32 bits (but does in 64 bits)? Fun times...

Re: Linking order of functions in VirtualBox + EFI32

Posted: Thu Oct 22, 2015 11:59 pm
by kzinti
OK here it is:

In 64 bits, efi_main's symbol stays "efi_main" in the final image.
In 32 bits, efi_main gets "decorated" to "_efi_main".

Fun times.

Re: Linking order of functions in VirtualBox + EFI32

Posted: Fri Oct 23, 2015 12:04 am
by kzinti
Just found confirmation that this is expected behaviour (https://en.wikipedia.org/wiki/Name_mangling)
In the stdcall and fastcall mangling schemes, the function is encoded as _name@X and @name@X respectively, where X is the number of bytes, in decimal, of the argument(s) in the parameter list (including those passed in registers, for fastcall). In the case of cdecl, the function name is merely prefixed by an underscore.

Note that the 64-bit convention on Windows (Microsoft C) has no leading underscore. This difference may in some rare cases lead to unresolved externals when porting such code to 64 bits. For example, Fortran code can use 'alias' to link against a C method by name as follows:
Loving this monologue =)

Re: Linking order of functions in VirtualBox + EFI32

Posted: Sun Oct 25, 2015 6:56 am
by jnc100
Glad you found the answer - yes, name mangling (on 32-bit) is one of the issues with using the MinGW tools for UEFI, however most UEFI systems are x86_64 compatible anyway, so if you use that instead it shouldn't be a problem. The other issue you may come across is that it defines some macros (like WINDOWS, WIN32 etc) which cause some third party libraries to think they are being built under windows, and therefore expect the presence of the full win32 sdk. You may have to edit some configure scripts/makefiles if trying to build things like zlib, libpng etc for your bootloader.

As an aside, the build commands in UEFI Bare Bones provide a way of setting the appropriate PE file headers without needing the separate objcopy step (which presumably needs a cross-compiled binutils?).

Regards,
John.

Re: Linking order of functions in VirtualBox + EFI32

Posted: Mon Oct 26, 2015 1:42 pm
by kzinti
I didn't need any cross-build, as the objcopy on my system already supported PE formats. But yes, I noticed the "-Wl,--subsystem,10" and now use that instead of invoking objcopy.

So far I haven't run into any issues with Windows definitions, but thanks for the heads up.

One issue I am struggling with right now is weak functions. I am defining weak functions in my libc implementation so that the consumer of libc (multiboot loader, efi loader, kernel, etc) can overwrite them. As an example, I declare puts() as a weak function. For some reason, MingW will not find that symbol at link time and complain about missing function "puts". This works fine with normal GCC.

I suspect it has to do with me putting libc objects into a library, I will play with the -whole-archive tonight and see where that gets me. But if you have any experience with this (weak symbols on MingW), please speak up =)

Re: Linking order of functions in VirtualBox + EFI32

Posted: Tue Oct 27, 2015 11:22 am
by kzinti
Looks like the issue is that weak symbols don't interact well with builtins. So if I define my own functions weak, everything works fine. If I declare puts() weak and use -fbuiltins, it won't resolve. If I do not use -fbuiltins, it works.

So, on MingW, make sure you don't enable builtins if you intend on declaring (some of) them as weak symbols. But with normal GCC, go wild.