UEFI in assembler

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.
newosdeveloper2021
Posts: 15
Joined: Sat May 01, 2021 8:47 pm

UEFI in assembler

Post by newosdeveloper2021 »

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
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: UEFI in assembler

Post by nullplan »

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.
Carpe diem!
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: UEFI in assembler

Post by zaval »

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.
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).
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: UEFI in assembler

Post by bzt »

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
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.
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
Korona
Member
Member
Posts: 1000
Joined: Thu May 17, 2007 1:27 pm
Contact:

Re: UEFI in assembler

Post by Korona »

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.
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].
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: UEFI in assembler

Post by nullplan »

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.
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.
Korona wrote:What others have said so far is correct. But let me ask for the "why?".
Well, the wisdom of doing any osdev at all can be disputed, but yeah, seconded. https://www.youtube.com/watch?v=wJ81MZUlrDo
That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
Carpe diem!
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: UEFI in assembler

Post by kzinti »

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
See https://mjg59.dreamwidth.org/18773.html?thread=1003605 as a starting point.
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.
This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.
nullplan wrote:That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
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.
vvaltchev
Member
Member
Posts: 274
Joined: Fri May 11, 2018 6:51 am

Re: UEFI in assembler

Post by vvaltchev »

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.
I totally agree with that.

Also:
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.
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.

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
rdos
Member
Member
Posts: 3297
Joined: Wed Oct 01, 2008 1:55 pm

Re: UEFI in assembler

Post by rdos »

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.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI in assembler

Post by Octocontrabass »

nullplan wrote:I was under the impression the image had to be position independent, or else the UEFI would refuse to load it.
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.)
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: UEFI in assembler

Post by zaval »

kzinti wrote: This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.
relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
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.
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).
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.)
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.
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).
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: UEFI in assembler

Post by kzinti »

zaval wrote: relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
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?

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.
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: UEFI in assembler

Post by zaval »

kzinti wrote:
zaval wrote: relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
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?

If I remove either -fpic or -pie, my bootloader stops working.
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.
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.
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).
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).
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: UEFI in assembler

Post by kzinti »

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:

Code: Select all

foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
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.
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI in assembler

Post by Octocontrabass »

kzinti wrote:So yeah... If you use mingw, you are actually generating position-independent code.
Despite the warning, GCC is generating the right 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.
Post Reply