"correct" way to generate EFI binaries?

Alexander von Gluck IV kallisti5@unixzen.com
Tue Jul 21 00:59:12 GMT 2020


July 20, 2020 7:42 PM, "Palmer Dabbelt" <palmer@dabbelt.com> wrote:

> On Fri, 10 Jul 2020 16:08:38 PDT (-0700), Jim Wilson wrote:
> 
>> On Wed, Jul 8, 2020 at 10:33 AM Jim Wilson <jimw@sifive.com> wrote:
> 
> On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
> <kallisti5@unixzen.com> wrote:
> riscv64 ( no Pe in bfd :-( )
> 
> I know that some work was done on this, but I don't know if it was
> finished, I don't know if they have copyright assignments, and I've
> never seen patches. If they do exist, they are probably somewhere in
> the edkii (aka edk2) source tree.
> https://riscv.org/wp-content/uploads/2016/01/Tues1415-RISC-V-and-UEFI.pdf
>> I just found this while looking for something else.
>> https://github.com/riscv/riscv-uefi-edk2-docs
>> This has binaries for a x86_64-linux cross riscv64 toolchain that
>> contains UEFI support. I've never tried any of this stuff myself.
> 
> IIRC they had some tool that converts ELF to PE for the UEFI stuff. We do
> something pretty simple in Linux where we objdump a flat binary with the PE
> header just written in assembly at the start (well, not quite yet -- we're
> actively not setting the PE magic bits as we don't quite have EFI yet).
> 
> If you want the combined PE/flat binaries then you need the C extension, as we
> rely on the PE magic number also being a valid instruction (the next
> instruction jumps past the rest of the header). If you only want PE binaries
> then you should be able to generate them for any ISA, but in Linux we intend on
> relying on a single binary being both PE and flat so it can run on any
> bootloader.
> 
> It's obviously far from a general solution, but if you have control over the
> software then it can work as long as you're careful. We didn't invent the
> scheme, it's from arm64 (and IIRC to a lesser extent event Intel).
> 
> Not sure what the original question was, though, so I don't know if that helps
> any :)

Thanks :-)

I've done a lot of research since I posted this and opened a few bugs/enhancements.

Essentially:

1. objcopy --output-target efi-app-x86_64 (that everyone seems to run) is undocumented
and generally was left in for compatibility.

2. objcopy --output-target pei-x86-64 --subsystem=efi-app is the "correct" invocation to
generate UEFI binaries with native binutils + bfd (and working for us)

3. On arm, objcopy --output-target pei-arm --subsystem=efi-app works to also produce
efi... err NOT efi binaries. This target is utterly broken on arm in binutils
and generates arm coff executables with "made up" arm architecture cpu ids in headers...
https://sourceware.org/bugzilla/show_bug.cgi?id=26218
(funny side story, the pei-wince-arm target looks to be a lot closer to the desired
format. I haven't tested it yet, but don't want to rely on it for all of my code)

4. On aarch64, objcopy --output-target pei-aarch64 doesn't exist.
https://sourceware.org/bugzilla/show_bug.cgi?id=26206
rinse and repeat for other valid EFI targets.

ld.lld seems to support all of these from my research, options for any future folk seeing
this:

1) Stick with gnu-efi and it's "fake pe" headers
2) Switch to ld.lld and generate PE binaries natively for EFI.
3) Use binutils, and don't target anything other than x86_64 :-)

-- Alex


More information about the Binutils mailing list