Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISCV64 driver does not have the proper EFI subsystem set #27

Closed
pbatard opened this issue May 20, 2024 · 5 comments
Closed

RISCV64 driver does not have the proper EFI subsystem set #27

pbatard opened this issue May 20, 2024 · 5 comments

Comments

@pbatard
Copy link
Contributor

pbatard commented May 20, 2024

Despite having an explicit --defsym=EFI_SUBSYSTEM=0xb in the linker command:

riscv64-linux-gnu-ld -nostdlib  --warn-common --no-undefined --fatal-warnings --build-id=sha1 -z nocombreloc -z norelro -L/home/runner/work/gnu-efi/gnu-efi//apps/../riscv64/lib -L/home/runner/work/gnu-efi/gnu-efi//apps/../riscv64/gnuefi /home/runner/work/gnu-efi/gnu-efi//apps/../riscv64/gnuefi/crt0-efi-riscv64.o -shared -Bsymbolic -L/home/runner/work/gnu-efi/gnu-efi//apps/../riscv64/lib --defsym=EFI_SUBSYSTEM=0xb drv0.o -o drv0.so -T /home/runner/work/gnu-efi/gnu-efi//apps/../gnuefi/elf_riscv64_efi.lds -lefi -lgnuefi /usr/lib/gcc-cross/riscv64-linux-gnu/11/libgcc.a

It seems that the EFI subsystem is not properly applied to the RISCV64 driver, as the riscv64 artifacts from the build that produced https://github.com/ncroxon/gnu-efi/actions/runs/9159433032/job/25179796521 show that the drv0.efi is still set as a UEFI Application (EFI_SUBSYSTEM=0xa):

Image1

This is also confirmed by trying to load the driver in with an UEFI firmware in QEMU RISCV64, which fails because of the wrong subsystem type.

Considering that we have an explicit:

#ifndef EFI_SUBSYSTEM
#define EFI_SUBSYSTEM 10
#endif

in gnuefi/crt0-efi-riscv64.S that we don't have in other archs, and that removing it produces the error:

gnuefi/crt0-efi-riscv64.S:70: Error: cannot represent BFD_RELOC_16 relocation in object file

I would think that the issue is that we need a delayed symbol resolution in crt0-efi-riscv64.o (since it goes into libgnuefi.a which we then link with the app, and which is the library that contains the PE header with the EFI_SUBSYSTEM field), that either we haven't figured how to do, or that the current RISCV64 toolchain doesn't support yet...

@gmbr3
Copy link
Contributor

gmbr3 commented May 22, 2024

Yep, no 16bit REL
(https://github.com/bminor/binutils-gdb/blob/92f59183ab085f5762650c3242a33119d161e668/bfd/elfxx-riscv.c#L973)
RISCV64 will have to use generator mode (like fwupd-efi) and/or objcopy
It can't support delayed symbol mode

@pbatard
Copy link
Contributor Author

pbatard commented May 22, 2024

Any chance we could just combine the 16-bit Subsystem and subsequent 16-bit DllCharacteristics into a 32-bit, since we have 32bit REL? DllCharacteristics is always zero for UEFI and we are dealing with little endian values, so, on paper, this looks like a simpler workaround.

However, while my testing doing just that compiles without throwing any error (and without the need for the #ifndef EFI_SUBSYSTEM), the resulting Subsystem and DllCharacteristics fields in the PE are always set to 0. Yet, if I change the name of the EFI_SUBSYSTEM variable in the .S to something else, the linker will throw an error about undefined reference for that other name, which tends to indicate that the linker does see the 32-bit EFI_SUBSYSTEM as a delayed symbol, but it somehow still fail to populate it with the value we pass in --defsym=EFI_SUBSYSTEM...

Am I missing something obvious? Or is just another RISCV64 toolchain limitation/bug?

@gmbr3
Copy link
Contributor

gmbr3 commented May 22, 2024

Yet, if I change the name of the EFI_SUBSYSTEM variable in the .S to something else, the linker will throw an error about undefined reference for that other name, which tends to indicate that the linker does see the 32-bit EFI_SUBSYSTEM as a delayed symbol, but it somehow still fail to populate it with the value we pass in --defsym=EFI_SUBSYSTEM...

That also seems weird 😕 , it should work like that.

Also DllCharacteristics is now populated by NX bit data for UEFI

@pbatard
Copy link
Contributor Author

pbatard commented May 22, 2024

Hmm, further testing shows that the value we pass in --defsym=EFI_SUBSYSTEM ends up in the .rodata section rather than in the header...

pbatard added a commit to pbatard/gnu-efi that referenced this issue May 23, 2024
The RISC64 do not support 16-bit variable relocation from assembly, and even
if it did support relocations, it would not properly set the subsystem from
--defsym. So we add an extra step on RISCV64, post objcopy, to set the field
manually (using dd and /bin/echo to output the relevant byte, as GNU Make's
echo does not support -ne).
Closes ncroxon#27.
@pbatard
Copy link
Contributor Author

pbatard commented May 23, 2024

All things considered, I think our best course of action for now is to just add an extra step to our build that sets the SubSystem property after the objcopy step, and I have just proposed a patchset that does this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants