"correct" way to generate EFI binaries?

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

"correct" way to generate EFI binaries?

Alexander von Gluck IV
Hello!

I see a lot of (external blog) documentation around using the
efi-app-x86_64 output target for EFI binaries.

This works for our (Haiku's) x86_64 EFI bootloaders:


objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym
  -j .rel -j .rela -j .reloc -j .dynstr
  --output-target=efi-app-x86_64 $(2) $(1)


Anything outside of x86_64 seems to use GNU-EFI's fake Pe
headers + binary output targets

(working arm EFI loader with "fake pe":

file arm/release/system/boot/efi/haiku_loader.efi
haiku_loader.efi: MS-DOS executable PE32 executable (EFI application) ARM Thumb (stripped to external PDB), for MS Windows



The (undocumented) efi-app-* target doesn't seem to exist
in bfd for any other architectures. (likely leading to this confusion.)


I've been doing some digging, and it *appears* that the following
is what folks are "supposed" to be using:


x86_64   --output-target=pei-x86-64     --subsystem=efi-app
arm      --output-target=pei-arm-little --subsystem=efi-app
aarch64  ( no Pe in bfd :-( )
riscv64  ( no Pe in bfd :-( )


However, EFI loaders generated with the above flags never
seem to boot properly and have screwy headers:


file x86_64/release/system/boot/efi/haiku_loader.efi
haiku_loader.efi: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows

file arm/release/system/boot/efi/haiku_loader.efi
haiku_loader.efi: PE Unknown PE signature 0x742e, for MS Windows



Is there a set of "correct" objcopy flags to generate EFI
Pe binaries for multiple architectures without using the
"fake Pe" header hacks in GNU-EFI?

I know Pe's the devil, and like you wish it was Elf.. but that
trolly has left the station :-)



 -- Alex
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Alexander von Gluck IV
July 8, 2020 8:37 AM, "Alexander von Gluck IV" <[hidden email]> wrote:

>
> Hello!
>
> I see a lot of (external blog) documentation around using the
> efi-app-x86_64 output target for EFI binaries.
>
> ...
>
> The (undocumented) efi-app-* target doesn't seem to exist
> in bfd for any other architectures. (likely leading to this confusion.)
>
> I've been doing some digging, and it *appears* that the following
> is what folks are "supposed" to be using:
>
> x86_64 --output-target=pei-x86-64 --subsystem=efi-app
> arm --output-target=pei-arm-little --subsystem=efi-app
> aarch64 ( no Pe in bfd :-( )
> riscv64 ( no Pe in bfd :-( )
>
> However, EFI loaders generated with the above flags never
> seem to boot properly and have screwy headers:

Scratch that. x86_64 EFI is working in this model (just missing -j's)

It seems like pei-arm-little + efi-app is simply broken in binutils?
(2.32)

> file arm/release/system/boot/efi/haiku_loader.efi
> haiku_loader.efi: PE Unknown PE signature 0x742e, for MS Windows

efi_analyzer/efianalyze arm/release/system/boot/efi/haiku_loader.efi

Offset to PE: 0x80
Machine type: 0x0a00, Unknown machine type
PointerToSymbolTable should be 0.
NumberOfSymbols should be 0.
Characteristics: 0x0105
  * Relocation information was stripped from the file.
  * COFF line numbers were stripped from the file.
  * The computer supports 32-bit words.
Wrong OHS Magic 0x742e
Image type: (crash in EFI analyzer tool)


 -- Alex
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Jim Wilson-2
On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
<[hidden email]> 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

Jim
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Alexander von Gluck IV
In reply to this post by Alexander von Gluck IV
July 8, 2020 12:23 PM, "Alexander von Gluck IV" <[hidden email]> wrote:

> July 8, 2020 8:37 AM, "Alexander von Gluck IV" <[hidden email]> wrote:
>
>> Hello!
>>
>> I see a lot of (external blog) documentation around using the
>> efi-app-x86_64 output target for EFI binaries.
>>
>> ...
>>
>> The (undocumented) efi-app-* target doesn't seem to exist
>> in bfd for any other architectures. (likely leading to this confusion.)
>>
>> I've been doing some digging, and it *appears* that the following
>> is what folks are "supposed" to be using:
>>
>> x86_64 --output-target=pei-x86-64 --subsystem=efi-app
>> arm --output-target=pei-arm-little --subsystem=efi-app
>> aarch64 ( no Pe in bfd :-( )
>> riscv64 ( no Pe in bfd :-( )
>>
>> However, EFI loaders generated with the above flags never
>> seem to boot properly and have screwy headers:
>
> Scratch that. x86_64 EFI is working in this model (just missing -j's)
>
> It seems like pei-arm-little + efi-app is simply broken in binutils?
> (2.32)
>
>> file arm/release/system/boot/efi/haiku_loader.efi
>> haiku_loader.efi: PE Unknown PE signature 0x742e, for MS Windows
>
> efi_analyzer/efianalyze arm/release/system/boot/efi/haiku_loader.efi
>
> Offset to PE: 0x80
> Machine type: 0x0a00, Unknown machine type
> PointerToSymbolTable should be 0.
> NumberOfSymbols should be 0.
> Characteristics: 0x0105
> * Relocation information was stripped from the file.
> * COFF line numbers were stripped from the file.
> * The computer supports 32-bit words.
> Wrong OHS Magic 0x742e
> Image type: (crash in EFI analyzer tool)
>

lol. Whell there's the problem:

http://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=include/coff/arm.h;h=93ce49c1d05114b7d4b1cdb5b88fd8a1f4f0e68e;hb=HEAD#l78

  78 #define ARMMAGIC        0xa00  /* I just made this up */

It looks like you have to use "wince" arm to get a semi-valid EFI booloader via ARMPEMAGIC?

http://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=bfd/coffcode.h;h=0910f918d13bf46394e3d3f3da40055fd2aa7a79;
hb=HEAD#l2754

Is there anyway to override the Pe machine type at build time?

Not sure of the correct fix here.


 -- Alex
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Jim Wilson-2
In reply to this post by Jim Wilson-2
On Wed, Jul 8, 2020 at 10:33 AM Jim Wilson <[hidden email]> wrote:
> On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
> <[hidden email]> 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.

Jim
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Palmer Dabbelt
On Fri, 10 Jul 2020 16:08:38 PDT (-0700), Jim Wilson wrote:

> On Wed, Jul 8, 2020 at 10:33 AM Jim Wilson <[hidden email]> wrote:
>> On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
>> <[hidden email]> 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 :)
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Alexander von Gluck IV
July 20, 2020 7:42 PM, "Palmer Dabbelt" <[hidden email]> 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 <[hidden email]> wrote:
>
> On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
> <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

Re: "correct" way to generate EFI binaries?

Andreas Schwab-2
In reply to this post by Palmer Dabbelt
On Jul 20 2020, Palmer Dabbelt 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 <[hidden email]> wrote:
>>> On Wed, Jul 8, 2020 at 10:23 AM Alexander von Gluck IV
>>> <[hidden email]> 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.

grub has grub-mkimage for that.

Andreas.

--
Andreas Schwab, [hidden email]
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."