UEFI in assembler
-
- Posts: 15
- Joined: Sat May 01, 2021 8:47 pm
UEFI in assembler
Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
Re: UEFI in assembler
Well, which is it? Do you want to learn in depth or do you want a tutorial. We have a UEFI tutorial in the Wiki for you to peruse at your leisure, and if you want to go in-depth, there is the UEFI specification. It's not very complicated. UEFI works with PE DLLs (essentially; you have to make sure your code is position independent). Chapter 4 of the spec tells you what your entry point looks like and most of the remaining chapters are a reference for all the services you can call. But just like you don't need to have all of Ralf Brown's Interrupt List memorized when creating a legacy bootloader, you don't need to know all of the UEFI spec to write a UEFI bootloader.
Unsurprisingly, the job of a bootloader (to load a file into memory) largely remains the same, but with UEFI you no longer have to limit yourself to 512 bytes.
Unsurprisingly, the job of a bootloader (to load a file into memory) largely remains the same, but with UEFI you no longer have to limit yourself to 512 bytes.
Carpe diem!
Re: UEFI in assembler
you just need to conform to the calling convention for the particular architecture, there is nothing special in interfacing your loader, written in assembly, with UEFI, that provides the C language specified interface. just like any other C and assembly interaction. if you want to learn deep UEFI, then the only way is studying its specification. And I second, it's absolutely not complex. especially shouldn't be for one, who wants to write in assembly.
nullplan confused something, telling you need your code to be position independent, it absolutely doesn't, rather opposite - your loader is a PE image and it will be loaded at some base, maybe that, you specify, if it's free. You need your assembler to be able to generate PE images.
nullplan confused something, telling you need your code to be position independent, it absolutely doesn't, rather opposite - your loader is a PE image and it will be loaded at some base, maybe that, you specify, if it's free. You need your assembler to be able to generate PE images.
Re: UEFI in assembler
The easiest would be with fasm (it has very good macro capabilities to use ABI wrappers and can generate PE executable with configurable subsystem). You'll need a function that converts standard calls to UEFI ABI, and then use the UEFI spec to figure out the parameters to each calls.newosdeveloper2021 wrote:Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
Both can be found on the wiki, the macro "uefi_call_wrapper" provides the ABI wrapper, and there are examples on how to read sectors, set screen resolution etc.
Cheers,
bzt
Re: UEFI in assembler
What others have said so far is correct. But let me ask for the "why?".
Using UEFI from assembler has zero benefits over using it from C. You mention that you want to learn UEFI in-depth but calling it from assembly will mainly teach you how to fight calling conventions and PIC idiosyncrasies and not really what UEFI is about. My 2¢: if you want to learn it in-depth, learn how it use it in C.
Using UEFI from assembler has zero benefits over using it from C. You mention that you want to learn UEFI in-depth but calling it from assembly will mainly teach you how to fight calling conventions and PIC idiosyncrasies and not really what UEFI is about. My 2¢: if you want to learn it in-depth, learn how it use it in C.
managarm: Microkernel-based OS capable of running a Wayland desktop (Discord: https://discord.gg/7WB6Ur3). My OS-dev projects: [mlibc: Portable C library for managarm, qword, Linux, Sigma, ...] [LAI: AML interpreter] [xbstrap: Build system for OS distributions].
Re: UEFI in assembler
I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.zaval wrote:nullplan confused something, telling you need your code to be position independent, it absolutely doesn't, rather opposite - your loader is a PE image and it will be loaded at some base, maybe that, you specify, if it's free. You need your assembler to be able to generate PE images.
Well, the wisdom of doing any osdev at all can be disputed, but yeah, seconded. https://www.youtube.com/watch?v=wJ81MZUlrDoKorona wrote:What others have said so far is correct. But let me ask for the "why?".
That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
Carpe diem!
Re: UEFI in assembler
See https://mjg59.dreamwidth.org/18773.html?thread=1003605 as a starting point.newosdeveloper2021 wrote:Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.nullplan wrote:I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.
Very few people are masochist enough to write a UEFI bootloader in assembly. It is unlikely that many people will be willing to take the time to help with this.nullplan wrote:That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
Re: UEFI in assembler
I totally agree with that.Korona wrote:What others have said so far is correct. But let me ask for the "why?".
Using UEFI from assembler has zero benefits over using it from C. You mention that you want to learn UEFI in-depth but calling it from assembly will mainly teach you how to fight calling conventions and PIC idiosyncrasies and not really what UEFI is about. My 2¢: if you want to learn it in-depth, learn how it use it in C.
Also:
If you really wanna avoid "crappy" tutorials, then read the spec, seriously. But, don't be scared: you won't need to read the WHOLE spec. Just some parts of it. If you find it too difficult, maybe you need to learn more about the theory behind operating systems and bootloaders in general. Also, you need to have some understanding about how C code gets compiled and linked, along with calling conventions etc. To build a UEFI application knowing what's going on, without blindly copy-pasting stuff from tutorials, you need to have some amount of knowledge and experience.newosdeveloper2021 wrote: Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials.
Could you be more specific and explain what do you find super-hard to understand in the UEFI spec?
Tilck, a Tiny Linux-Compatible Kernel: https://github.com/vvaltchev/tilck
Re: UEFI in assembler
When I started with UEFI, the biggest problem was an environment that could create EFI files. I'm not on Linux, and I don't have M$ compilers, only OpenWatcom. However, I solved it by installing cygwin, both the 32-bit and the 64-bit version (on different computers) and downloaded GCC.
I actually was pondering to use assembly too, so I could avoid cygwin / Linux dependencies in my project. I eventually solved it by checking in the efi-executables into my SVN so I don't have to build them.
I actually was pondering to use assembly too, so I could avoid cygwin / Linux dependencies in my project. I eventually solved it by checking in the efi-executables into my SVN so I don't have to build them.
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: UEFI in assembler
EFI binaries are supposed to be relocatable, which is almost the same as position-independent. I don't think the UEFI spec says anything about what will happen if your binary isn't relocatable. (OVMF will load it anyway, which makes it difficult to tell if your linker options are correct.)nullplan wrote:I was under the impression the image had to be position independent, or else the UEFI would refuse to load it.
Re: UEFI in assembler
relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.kzinti wrote: This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.
You don't have to know free addresses, your PE image uses some as a base, it may be even 0; then the FW, when loading the image, looks if it can place it at this address, if it can, then that's all, if not, it relocates the image, fixing (changing) all the references to the absolute addresses, both in code and data. That's why it's not PIC, because PIC means no references to absolute addresses at all, all references are relative, for example, to the program counter. Then putting an image somewhere else wouldn't require fixing anything, since for example a reference "load word into reg R from the memory, that is N bytes above program counter" remains the same. Position dependent then would be "load word into reg R from the memory at the address A0". That's exactly what PE uses. if the image has been put not at the preferred base, then A0 needs to be changed to A1, before the image starts execution. It applies both to exes and dlls. loaders are exes. dlls would be something that imports/exports from/to other images. unfortunately, UEFI doesn't make use this feature (for example exporting Boot Services/Runtime Services is an obvious case, but they decided to invent almost the same instead, resulting in an uglier code).nullplan wrote: I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.
The only way to make a PE image non-relocatable is to strip relocation information. If you do this and the image really has a non empty .reloc section and the preferred base, the image has been linked to isn't available, the FW has zero chances to start it. Unless it includes instruction decoder and some euristic to guess if these data (in the data sections) are pointers or something else.EFI binaries are supposed to be relocatable, which is almost the same as position-independent. I don't think the UEFI spec says anything about what will happen if your binary isn't relocatable. (OVMF will load it anyway, which makes it difficult to tell if your linker options are correct.)
Re: UEFI in assembler
I understand the difference. You still need to compile your UEFI bootloader as PIC and link it as PIE. At least you do when using GCC. Do you have a different experience?zaval wrote: relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
If I remove either -fpic or -pie, my bootloader stops working.
Every source I can find says that EFI needs position-independant code (i.e. -fpic). This appears to be the way you tell GCC to build a relocatable binary.
Re: UEFI in assembler
That's the weirdness of GCC (or even that gnu-efi cruft), that has nothing to do with either the PE image format or UEFI. I don't use GCC.kzinti wrote:I understand the difference. You still need to compile your UEFI bootloader as PIC and link it as PIE. At least you do when using GCC. Do you have a different experience?zaval wrote: relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
If I remove either -fpic or -pie, my bootloader stops working.
for some incomprehensible reasons, this way, they produce an ELF shared object (that needs to be PIC) and wrap it into PE, instead of targetting PE directly... It's just, the right tool needs to be used, a normal PE generating compiler toolset, in this case. If you can't use MSVC, then Clang maybe? But anyway, that -fpic option for building an UEFI application is a useless artifact, forced on you by the strange attitude of gnu/folks. Still I believe, that mingw thing should be free of this nonsense (given gnu-efi is ditched as well, of course).Every source I can find says that EFI needs position-independant code (i.e. -fpic). This appears to be the way you tell GCC to build a relocatable binary.
Re: UEFI in assembler
I have used mingw in the past and it is much easier to build an UEFI app with it (you don't need any of the gnu-efi trickeries).
That said, mingw actually forces fpic on you. It doesn't magically disappear. Here is what happens if you specify "-fpic" on the command line with mingw:
So yeah... If you use mingw, you are actually generating position-independent code.
You are also right that PE doesn't require it.
Ah the joys of computer programming.
That said, mingw actually forces fpic on you. It doesn't magically disappear. Here is what happens if you specify "-fpic" on the command line with mingw:
Code: Select all
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
You are also right that PE doesn't require it.
Ah the joys of computer programming.
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: UEFI in assembler
Despite the warning, GCC is generating the right code.kzinti wrote:So yeah... If you use mingw, you are actually generating position-independent code.
PE does require RIP-relative addressing if the executable might be loaded above 2GB. That's probably the reason why PIC is always enabled for 64-bit Windows targets.