GCC target PE32+

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
PeterX
Member
Member
Posts: 590
Joined: Fri Nov 22, 2019 5:46 am

GCC target PE32+

Post by PeterX »

Is there a GCC cross compiler target PE32+ (64bit PE) ?

EDIT: I don't want the compiler readymade from someone else. I just want to know whether I can build a cross compiler for PE32+.

Greetings
Peter
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: GCC target PE32+

Post by bzt »

PeterX wrote:Is there a GCC cross compiler target PE32+ (64bit PE) ?
Yeah, sure. But you don't need a cross-compiler, the simple way out is to compile to ELF as usual and as a last step call objconv or objcopy to convert the output to PE.

Otherwise you can compile gcc and binutils for PE target, pretty much the same way as you would with any other targets. There are many projects that already done this, MinGW for Linux pops into my mind. It is very likely that you can access it from your distro's standard repo, but if not, download it from the linked page. (FYI: MinGW is not the only one, there are others. It's just the simplest to use to my humble opinion.) Try

Code: Select all

sudo apt-get install gcc-mingw-w64
I haven't tried it, but CLang should be able to compile to PE on Linux. (I've used it for cross-compiling, works out-of-the-box, just I haven't tried with a pe triplet in particular.) Try wclang.

Cheers,
bzt
PeterX
Member
Member
Posts: 590
Joined: Fri Nov 22, 2019 5:46 am

Re: GCC target PE32+

Post by PeterX »

OK, maybe what I'm trying to do is not so smart. Let's see:

The whole thing I'm trying to do is producing an UEFI application.

I thought of producing PE32+ as an UEFI application.
EDK2 and GNU-EFI can do that. But it's a pain and I think I could reduce or replace the dependencies (for me and maybe for others).

I thought: Let's produce an normal object file from C source-code file using GCC. As it seems this could be a 64bit ELF or COFF (both should work).
And then link a little assembler object file with the object file from GCC together to a PE32+ UEFI application.
(The assembler object file would NOT replace a standard C library with main() etc.)

Is the whole thing obsolete? I managed to build EDK II and OVMF, but it still is difficult to produce a UEFI application with it, because you need to edit a DSC file and produce in inf file. And the GNU-EFI include file seems not very mature.

Greetings
Peter
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: GCC target PE32+

Post by nexos »

Have you looked at this tutorial?
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
PeterX
Member
Member
Posts: 590
Joined: Fri Nov 22, 2019 5:46 am

Re: GCC target PE32+

Post by PeterX »

nexos wrote:Have you looked at this tutorial?
Wow, thanks, I didn't see that.
That gives me some stuff to read. Looks like it is what am asking about :) :)

Greetings
Peter
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: GCC target PE32+

Post by nexos »

Glad I could be of help :D
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: GCC target PE32+

Post by bzt »

PeterX wrote:I thought of producing PE32+ as an UEFI application.
EDK2 and GNU-EFI can do that.
Let's not mix these two, they use different approach. For the EDK, it internally uses PE. For GNU-EFI, it always uses the native toolchain and convert to PE in the last step.
PeterX wrote:But it's a pain and I think I could reduce or replace the dependencies (for me and maybe for others).
Take a look at my boot loader. I've managed to shrink the build environment considerably: BOOTBOOT x86_64-efi. Here crt0 is what its look like. The lds file is a linker script. The files libefi.a provides mostly GUIDs and high level functions (like Print()) and libgnuefi.a the low level stuff (like uefi_call_wrapper()). That's all, no third party dependencies.
PeterX wrote:I thought: Let's produce an normal object file from C source-code file using GCC. As it seems this could be a 64bit ELF or COFF (both should work).
And then link a little assembler object file with the object file from GCC together to a PE32+ UEFI application.
Check out my Makefile, it compiles everything into ELF (on Linux), and then uses objcopy convert it into PE. There are many gotchas during this process, see how many flags I had to use, but at the end of the day I can compile EFI applications with native GNU toolchain, without requiring anything special. So what you had in mind is perfectly doable :-)
PeterX wrote:I managed to build EDK II and OVMF, but it still is difficult to produce a UEFI application with it,
True, it is a real pain in the @ss.
PeterX wrote:And the GNU-EFI include file seems not very mature.
Also true, however it has almost everything you need for a bootloader. And for those few things that it might lack, you can always add some structs and a GUID in you app, it is not a big deal.

Cheers,
bzt
User avatar
zaval
Member
Member
Posts: 657
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: GCC target PE32+

Post by zaval »

just don't forget, that all these "converters" are snake oil and they in fact DON'T LET you use PE at full potential - import/export etc. for this, you need a compiler that DOES support PE targetting.

an easy example: no __declspec(dllimport). no IAT, bye. it's a compiler task, not some postprocessing mumbojumbo utility. you declare a function as dllimported and the compiler calls it differently, say
call [__imp_IsSh1tDone]
instead of
call IsSh1tDone

that symbol is a IAT residing pointer.
you see, it's a code generation thing - to make the former call instead of, a common, latter. not postprocessing. what all those converters do is crippled down PEs. for example neither edk (I guess, I am sure) nor UEFI applications don't make use import/export mechanism. but the fully fledged environment would want to use it.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
PeterX
Member
Member
Posts: 590
Joined: Fri Nov 22, 2019 5:46 am

Re: GCC target PE32+

Post by PeterX »

zaval wrote:just don't forget, that all these "converters" are snake oil and they in fact DON'T LET you use PE at full potential - import/export etc. for this, you need a compiler that DOES support PE targetting.

an easy example: no __declspec(dllimport). no IAT, bye. it's a compiler task, not some postprocessing mumbojumbo utility. you declare a function as dllimported and the compiler calls it differently, say
call [__imp_IsSh1tDone]
instead of
call IsSh1tDone

that symbol is a IAT residing pointer.
you see, it's a code generation thing - to make the former call instead of, a common, latter. not postprocessing. what all those converters do is crippled down PEs. for example neither edk (I guess, I am sure) nor UEFI applications don't make use import/export mechanism. but the fully fledged environment would want to use it.
Ah, I see what you mean. I will keep that in mind if I ever write a PE32+ kernel. For now I stick to (simple) UEFI applications.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: GCC target PE32+

Post by bzt »

zaval wrote:just don't forget, that all these "converters" are snake oil and they in fact DON'T LET you use PE at full potential - import/export etc.
You should not use PE dll import/export function under UEFI at all! Your code will suck and will break on various firmware! UEFI was never designed to handle dlls!

Under UEFI, PE is just a container format for a single (but relocateable) code image file. All the firmware provided interfaces are "dynamically linked" by querying their addresses using LocateHandle or OpenProtocol etc. If you want dynamic linking, you should register such handles in your modules too, and use LocateHandle and friends in your main app. To assure ABI compatibility, GNU EFI provides "uefi_call_wrapper" function, always use that, and any C compiler will do!

But more importantly, who does need complex infrastructure for pre-OS environment (other that rootkits and spyware I mean)?
Just make it load your kernel and get the hell out of there as soon as possible!

Cheers,
bzt
PeterX
Member
Member
Posts: 590
Joined: Fri Nov 22, 2019 5:46 am

Re: GCC target PE32+

Post by PeterX »

bzt wrote:Just make it load your kernel and get the hell out of there as soon as possible!
Yeah, after reading the several answers I come to the same conclusion. I intend to write
1.) Hello World
2.) system info
3.) minimal kernel loader
All both for learning and for giving example code to other people.

Greetings
Peter
User avatar
zaval
Member
Member
Posts: 657
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: GCC target PE32+

Post by zaval »

bzt wrote:
zaval wrote:just don't forget, that all these "converters" are snake oil and they in fact DON'T LET you use PE at full potential - import/export etc.
You should not use PE dll import/export function under UEFI at all! Your code will suck and will break on various firmware! UEFI was never designed to handle dlls!

Under UEFI, PE is just a container format for a single (but relocateable) code image file. All the firmware provided interfaces are "dynamically linked" by querying their addresses using LocateHandle or OpenProtocol etc. If you want dynamic linking, you should register such handles in your modules too, and use LocateHandle and friends in your main app. To assure ABI compatibility, GNU EFI provides "uefi_call_wrapper" function, always use that, and any C compiler will do!

But more importantly, who does need complex infrastructure for pre-OS environment (other that rootkits and spyware I mean)?
Just make it load your kernel and get the hell out of there as soon as possible!

Cheers,
bzt
first of all, this topic has nothing to do with UEFI. its author asked this question:
Is there a GCC cross compiler target PE32+ (64bit PE) ?
kind of more general, than about UEFI, right?
second, it's up to the implementation of the UEFI - using PE import/export or not, internally it can perfectly use it. where it's not used (unfortunately) - is with UEFI<->UEFI application interface. here, it's duplicated by numerous function pointers.
finally, "to assure ABI compatibility" one uses proper compiler. ;) I use msvc, but I read some blog, where a guy used clang on linux and it worked perfectly fine for him without needless wrappers. however msvc can produce efi for x86, x64, arm and arm64. :)
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
nullplan
Member
Member
Posts: 1792
Joined: Wed Aug 30, 2017 8:24 am

Re: GCC target PE32+

Post by nullplan »

zaval wrote:kind of more general, than about UEFI, right?
Yeah, and two posts later, he added:
PeterX wrote:The whole thing I'm trying to do is producing an UEFI application.
zaval wrote:finally, "to assure ABI compatibility" one uses proper compiler. ;) I use msvc, but I read some blog, where a guy used clang on linux and it worked perfectly fine for him without needless wrappers. however msvc can produce efi for x86, x64, arm and arm64. :)
Yeah, you can also just tell GCC which calling convention to use by default, or just mark all external functions with the required attribute. But apparently that would be too hard, so people use uefi_call_wrapper, which eliminates compiler type checking. Because I really wanted to get rid of assembler, and so here I am writing assembler in C. *sigh*

Anyway, GCC can also be compiled for Windows, and will then generate PE32 or PE32+ executables. Even with the right calling convention. Of course, it is entirely up to taste which one to use. Except I can't use MSVC since I'm on Linux, but whatever blows your skirt up.
Carpe diem!
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: GCC target PE32+

Post by bzt »

nullplan wrote:just mark all external functions with the required attribute. But apparently that would be too hard, so people use uefi_call_wrapper, which eliminates compiler type checking.
I prefer uefi_call_wrapper over other solutions not because others would be hard, but because it is a clean 100% portable solution. Compiler attributes are not, they tie you to a certain compiler. True, you have to do the type checking yourself, but I have no issues with that, I can do that for those few functions I use (it's not more complicated than using printf). I value more that my sources can be compiled with any standard ANSI C compiler, let's say with tcc too for example. I always use as few compiler specific things as possible. But maybe this is just my preference.

Cheers,
bzt
Post Reply