Re: Debugging UEFI Issues on real hardware (POSIX-UEFI)
Posted: Mon Jul 19, 2021 5:21 pm
You still need relocations on x86_64 because some UEFI firmwares will not load your UEFI app if it doesn't contain any relocation.
The Place to Start for Operating System Developers
https://f.osdev.org/
I'm curious about this. Do you know which particular firmwares exhibit this? Is it really "if it doesn't contain any relocation" or is it "if it is marked as having relocations stripped"? I've definitely seen the latter behaviour in the Ovmf firmware, but not the former.kzinti wrote:You still need relocations on x86_64 because some UEFI firmwares will not load your UEFI app if it doesn't contain any relocation.
Funny, I've seen OVMF load and execute a binary where I had accidentally stripped the relocations and it ran perfectly fine. I only caught the issue when I saw Mingw-w64 objdump wasn't showing HAS_RELOC. Unless that's a different flag?davmac314 wrote:Is it really "if it doesn't contain any relocation" or is it "if it is marked as having relocations stripped"? I've definitely seen the latter behaviour in the Ovmf firmware, but not the former.
I took this information from GNU-EFI and you might be right. I have not actually tested without relocations on any firmware.davmac314 wrote:I'm curious about this. Do you know which particular firmwares exhibit this? Is it really "if it doesn't contain any relocation" or is it "if it is marked as having relocations stripped"? I've definitely seen the latter behaviour in the Ovmf firmware, but not the former.
GNU EFI does include a hack to make sure there is at least one PE-style relocation in the output PE image, but AFAICT that was to prevent objcopy from (wrongly) setting the "relocations stripped" flagged, not because the firmware actually requires a relocation to be present. I've definitely been able to execute an EFI image which had no relocations on that firmware.
I think HAS_RELOC might be a BFD-specific flag (i.e. a flag internal to binutils), The flag in the actual PE header is called IMAGE_FILE_RELOCS_STRIPPED (and it has the inverse meaning of course), see: http://docwiki.embarcadero.com/RADStudi ... s_(Delphi)Octocontrabass wrote:Funny, I've seen OVMF load and execute a binary where I had accidentally stripped the relocations and it ran perfectly fine. I only caught the issue when I saw Mingw-w64 objdump wasn't showing HAS_RELOC. Unless that's a different flag?davmac314 wrote:Is it really "if it doesn't contain any relocation" or is it "if it is marked as having relocations stripped"? I've definitely seen the latter behaviour in the Ovmf firmware, but not the former.
The only difference between my intended 64-bit binary and the accidentally stripped one is IMAGE_FILE_RELOCS_STRIPPED. (Also timestamps and checksums, but those don't matter here.) I'm using a cross-compiler, not the GNU-EFI hack.davmac314 wrote:My guess would be objdump reports "HAS_RELOC" if IMAGE_FILE_RELOCS_STRIPPED isn't set, but it might also (or instead) depend on the presence of a relocation section (.reloc).
That would make sense. The binaries I was testing had ImageBase set to 0x400000, so they would easily fit into available memory in the default QEMU+OVMF configuration.davmac314 wrote:It's possible that OVMF will run an EFI with relocs stripped *if* it can load it at its nominal address (i.e. without needing to perform any relocations); I'm not sure.
The version of Mingw-w64 objdump I'm using does report the PE header flags, but it doesn't use the names from the PE documentation.davmac314 wrote:(I used a utility called "readpe" to check actual PE header flags rather than rely on what objdump told me).
that is, this flag is 1) not to indicate, that an image is naturally position independent (because of PC/IP-relative accesses), but that this file must go where it's linked to. and 2) it's default for EXEs, which are main modules for programs and there is no reason to not place it where it wants. Note, however, that UEFI OS Loaders are being linked as DLLs (by sane compilers) and thus relocations are never get stripped, it's just there might be none of them. but the latter case cannot cause FW to refuse loading such an image.Image only, Windows CE, and
Windows NT® and later. This indicates
that the file does not contain base
relocations and must therefore be
loaded at its preferred base address. If
the base address is not available, the
loader reports an error. The default
behavior of the linker is to strip base
relocations from executable (EXE) files.
You've got some old information there. Neither MSVC nor Clang strip relocations when they generate EXEs. (GCC still does, for some reason.) Relocations are required for ASLR.zaval wrote:and 2) it's default for EXEs, which are main modules for programs and there is no reason to not place it where it wants.
No sane compiler links UEFI applications as DLLs. With MSVC and Clang, you don't need to do anything special since relocations are not stripped by default. GCC has the "-pie" flag.zaval wrote:Note, however, that UEFI OS Loaders are being linked as DLLs (by sane compilers) and thus relocations are never get stripped, it's just there might be none of them.
I don't think, MSVC linker v14.20 is old and I didn't do anything special, except setting /subsystem:EFI_APPLICATION and here is what it produces:Octocontrabass wrote: No sane compiler links UEFI applications as DLLs. With MSVC and Clang, you don't need to do anything special since relocations are not stripped by default. GCC has the "-pie" flag.
I've seen a few guides that recommend linking UEFI applications as DLLs, but I'm not sure why.
as of not stripping relocations by default for EXEs, I see, it's true, but the quoted was from the current PE spec.E:\Valera>dumpbin /headers out\antosldr\aarch64\antload.efi
Microsoft (R) COFF/PE Dumper Version 14.20.27508.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file out\antosldr\aarch64\antload.efi
PE signature found
File Type: DLL
FILE HEADER VALUES
AA64 machine (ARM64)
4 number of sections
60D14129 time date stamp Tue Jun 22 04:47:21 2021
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
2022 characteristics
Executable
Application can handle large (>2GB) addresses
DLL
Note that If compiling with GCC and linking with GNU ld (to `pei-XXX` format eg pei-x86-64) you can use `--emit-reloc-section` at link time (possibly requires `-mi386pep` linker emulation setting) rather than `-fpie` at compile time, if you want to preserve relocations (rather than eliminate the need for them, which is what `-fpie` achieves).Octocontrabass wrote:No sane compiler links UEFI applications as DLLs. With MSVC and Clang, you don't need to do anything special since relocations are not stripped by default. GCC has the "-pie" flag.
Only if there are dynamically linked libraries, which in the case of an EFI application there are not. The GOT isn't needed, since every variable is local to the application itself. In this case using -fpie produces an executable which neither has nor requires any relocations. (In contrast, -fpic will create a GOT regardless).zaval wrote:I am not sure what effect the gcc's -pie flag would have on PE targets, if any. in the ELF context, it's a total opposite to the PE approach, and it hardly would work for the latter, because PE loader does apply base relocations, that is fixes up addresses in the code and data itself, while -pie would require fixing up the contents of a special indirection table (GOT)
Interesting! It's been a while since I looked, so maybe I remembered wrong. (Or maybe MSVC is not a sane compiler.) Doesn't the PE spec say DLLs aren't supposed to be executed directly?zaval wrote:File Type: DLL
It tells Mingw-w64 GCC to use linker options that preserve relocations. I don't know if this applies to all PE targets or just Mingw-w64; I don't use any of GCC's other PE targets.zaval wrote:I am not sure what effect the gcc's -pie flag would have on PE targets, if any.
Hold on, there's a difference between "-fpie" and "-pie". Mingw-w64 GCC ignores options like "-fpie"; it unconditionally generates relocatable code. Only link options like "-pie" have any effect. I haven't checked exactly how "-pie" changes the options passed to the linker when linking with GCC.davmac314 wrote:Note that If compiling with GCC and linking with GNU ld (to `pei-XXX` format eg pei-x86-64) you can use `--emit-reloc-section` at link time (possibly requires `-mi386pep` linker emulation setting) rather than `-fpie` at compile time, if you want to preserve relocations (rather than eliminate the need for them, which is what `-fpie` achieves).
It says this about that flag:Interesting! It's been a while since I looked, so maybe I remembered wrong. (Or maybe MSVC is not a sane compiler.) Doesn't the PE spec say DLLs aren't supposed to be executed directly?
what is true for a usual OS environment. UEFI environment differs from the former, obviously, but again, the flag is used here for practical reasons (preserving relocations), but if to think about technicalties, then an UEFI application is not a standalone program, running in its own address space and thus - its image doesn't constitute the main module for that process, that after starting will possess its own address space, the image gets loaded into the existing address space of the firmware process, so, it's DLL in the sense, that it's not the main image, but loadable, secondary one. or, it's more like a driver - an OS loading driver. and drivers are a kind of DLLs.The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run.