Calling own function results in an crash

I want to call functions defined in my header files but this results in my uefi application to crash. (After the intended call the following print statements are not executed so I assume an crash.) I use gnu-efi but I am not sure if I am doing something gnu-efi specific or uefi general wrong. Everything compiles without warnings or errors and removing the "problem-function" causes the program to work (I can execute my efi file and the print statements work).

My main.c file:

#include "gnu-efi/inc/efi.h"
#include "gnu-efi/inc/efilib.h"
#include <inttypes.h>
#include "conversion.h"

efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {

   InitializeLib(ImageHandle, SystemTable);
   CONVSTRING(numstr) = L"00000000000000000000";
   ui64str(numstr, 5);   //The line causing the problem
   Print(L"Hello, world!\n");
   return EFI_SUCCESS;

My conversion.h file:

#include "gnu-efi/inc/efi.h"

#define CONVSTRING(name) CHAR16 name[21]

// String has to be the length of 21
void ui64str(CHAR16* string, uint64_t number);

My conversion.c file:

#include "gnu-efi/inc/efi.h"
#include "conversion.h"

void ui64str(CHAR16* string, uint64_t number)
    // "clear" string
    string = L"00000000000000000000";

(If needed I use a batch-script to build every thing)

gcc main.c                     \
    -c                         \
    -fno-stack-protector       \
    -fpic                      \
    -fshort-wchar              \
    -mno-red-zone              \
    -I gnu-efi/inc             \
    -I gnu-efi/inc/x86_64      \
    -I .                       \
    -o tmp/main.o

ld tmp/main.o                                   \
   gnu-efi/x86_64/gnuefi/crt0-efi-x86_64.o      \
   -nostdlib                                    \
   -znocombreloc                                \
   -T gnu-efi/gnuefi/         \
   -shared                                      \
   -Bsymbolic                                   \
   -L gnu-efi/lib                               \
   gnu-efi/x86_64/gnuefi/libgnuefi.a            \
   gnu-efi/x86_64/lib/libefi.a                  \
   -o tmp/

objcopy -j .text                \
        -j .sdata               \
        -j .data                \
        -j .dynamic             \
        -j .dynsym              \
        -j .rel                 \
        -j .rela                \
        -j .reloc               \
        --target=efi-app-x86_64 \
        tmp/             \

>Solution :

Your build script does not actually build conversion.c into an object file or link it. While you do textually include the header, a header is enough for a compiler to know declarations and prototypes, but it is not enough for the linker to actually link the definitions into the final binary.

Because of the way that you’re linking, you never actually get a link-time Unresolved Reference error – ld doesn’t mind when compiling with -shared1, and objcopy doesn’t mind the unresolved reference either.

You’ll need to ensure that you actually build and link conversion.c. The simplest approach would be to add a second similar gcc command that builds conversion.o from the source in conversion.c, and then add conversion.o to your ld command line.

1 My instinct (and other readers instinct) may be to assume that the EFI executable should be statically linked; this page explains the rationale – a shared, relocatable library is built and then objcopy’ed into a final EFI binary. This does seem a tad brittle however.

Leave a Reply