Author Topic: Compiling EFI file from ASM code  (Read 21156 times)

Offline JD9999

  • Jr. Member
  • *
  • Posts: 7
  • Country: au
Compiling EFI file from ASM code
« on: July 11, 2021, 05:42:55 AM »
I have written (what I believe to be) a very simple UEFI implementation is asm. It does nothing fancy.

I can compile this to an object file (.o file), but I don't know how to turn a .asm into a .efi that I can use to boot off a USB stick.

Please tell me if you know how to convert this into an EFI file.

I am using Windows 10, NASM 2.15.05, administrator privileges.

My code is attached below in case that helps.

Code: [Select]
BITS 64

global start

start:
;Start moving handoff variables
mov [EFI_HANDLE], rcx
mov [EFI_SYSTEM_TABLE], rdx
mov [UEFI_RETURN], rsp

        ;Do more here in the future

;Done!
mov rax, EFI_SUCCESS
ret

; Declare constants and variables here
EFI_HANDLE dq 0
EFI_SYSTEM_TABLE dq 0
UEFI_RETURN dq 0

EFI_SUCCESS db 0

Thanks,
JD9999

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Compiling EFI file from ASM code
« Reply #1 on: July 12, 2021, 03:45:49 AM »
Hi JD9999.

Welcome to the Forum!

I have no idea. :(

Does this give you any help?

https://wiki.osdev.org/UEFI

What have you tried? ...and what happened?

I'm  ASSuming:
Code: [Select]
nasm -f win64 myprog.asm
?
or?

What linker do you normally use? Any help in its documentation?

Hope for help from Windows users! Good luck!

Best.
Frank


Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Compiling EFI file from ASM code
« Reply #2 on: July 12, 2021, 04:04:43 AM »
further thoughts...

I would expect a bootable file to be assembled as:
Code: [Select]
nasm -f bin -o myfile.bin myfile.asm

The form of your code suggests that it is to be called and is to return. This would not be thecase with a binary file. So I'm confused...

Best,
Frank


Offline JD9999

  • Jr. Member
  • *
  • Posts: 7
  • Country: au
Re: Compiling EFI file from ASM code
« Reply #3 on: July 13, 2021, 04:48:42 AM »
Thanks Frank for your response!

I have been reading OSDev's articles of UEFI, as well as the bare bones article (but that's with C, not asm).
The main thing I've been looking at is https://github.com/BrianOtto/nasm-uefi, which is a successful implementation.
For the moment, I have copied a bit of his code, but I would like to not just copy it so that I understand what is happening.

I don't use linkers, because it's only one file, and I believe I don't need a header file (though I could be wrong).

I have managed to make a .o file, a .obj file, and a .bin file from this code, so I know that it definitely compiles. And in theory it should work, because all it does is retrieve the variables from the UEFI, and then return back to the UEFI. (Not like traditional BIOS, where the application can't give control back to the BIOS)

There is a script on Brian Otto's Github (in link above) that copies the file onto an emulated VHS and runs it off that, but that doesn't give me an EFI file. The other thing I've been looking at is https://forum.nasm.us/index.php?topic=2191.0. However, I don't understand the code in the OP's (of that thread) solution at all, and according to another user on the thread, it doesn't work (though that may be 32 bit vs 64 bit, or the other error the user points out).

My issue is how to compile the code so that it becomes an EFI file.

I hope this helps!

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Compiling EFI file from ASM code
« Reply #4 on: July 14, 2021, 04:31:47 AM »
Wow.
I am so far over my head I can't even see daylight.

I just came across this in nntp:alt/os/development

https://wiki.osdev.org/UEFI#UEFI_vs._legacy_BIOS

If anything, I'm even more confused than before.

They seem to say we need a PE executable. Okay, we can do that... with a linker or in -f bin mode. A header like UNIXMAN shows? Maybe "not quite"?
Fasm supposedly knows how to do this. If all else fails, we can copy Fasm. As you say. it would be nice to understand it...

I don't even know where to start. You show some code that uses symbols. These symbols must be defined somewhere or Nasm would barf, no? You must have used -f bin for the bin file. -f win64 for the .o or .obj files? Or did you just change the name? Are you shooting for real hardware or an emulation?

I just read that IDE drives are recommended. I had IDE drives in my old computer... but it crashed and the new one won't take 'em. I would love to have my IDE drives back, so I may be doubly "blessed"... I don't know whether I have UEFI... or what sort... I probably am not going to be able to help you much. We can discuss it...

Best,
Frank




Offline JD9999

  • Jr. Member
  • *
  • Posts: 7
  • Country: au
Re: Compiling EFI file from ASM code
« Reply #5 on: July 14, 2021, 05:39:19 AM »
Thanks Frank!

I found the command from BrianOtto's script that supposedly converts the .obj to .efi (using Visual Studio Link), but it hasn't worked. Instead, it's given me the error output you can see in the attached image file. Interestingly, it is Visual Studio that is unhappy, but NASM seems to be fine.

You're right about the PE header. It could be that there's an offset issue because I don't have the PE header. At the moment I'm looking at these articles to try to make one:
https://wiki.osdev.org/PE <-- particularly helpful
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#general-concepts
https://tech-zealots.com/malware-analysis/pe-portable-executable-structure-malware-analysis-part-2/
https://blog.kowalczyk.info/articles/pefileformat.html

I'll try it sometime in the next couple of days and let you know the result!

I'm trying to make it so it runs on a real machine (e.g. my 8th gen i7), so I don't want to use an IDE or VHS. once I have an EFI file, I know I can put it in a folder on my USB which *should* make it bootable. That's what I'm aiming for.

Thanks,
Jamie

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 373
  • Country: br
Re: Compiling EFI file from ASM code
« Reply #6 on: July 14, 2021, 01:57:27 PM »
As for the linker, I prefer to use GCC's ld and objcopy (as in osdev article). On Linux, you can compile with nasm to elf64 format and link in the same format, using objcopy you get rid of unecessary sections and convert your binary to PE+ format using --target=efi-app_x86_64 option:

Code: [Select]
; boot.asm
  bits  64
  default rel   ; x86_64 default effective address calculations should be always RIP relative.
 
  section .text

  ; ..start is the default entry point for ld.
  global _start
_start:

  mov   rcx,[rdx+64]    ; Get SysInfo ptr.
  lea   rdx,[hello]     ; Argument for Print.
  call  [rcx+8]         ; Call Service.

  ; Here you should call ExitBoot?!
  ret

  section .rodata

  ; Strings are always in UTF16 for EFI.
hello:
  db __utf16__ `hello, world!\r\n\0`

Code: [Select]
$ nasm -f elf64 -o boot.o boot.asm
$ ld -znocombreloc -shared boot.o -o boot.so
$ objcopy -j .text -j .data -j .rodata -j .bss -j .dynamic -j .dynsym -j .rel -j .rela -j .reloc \
   --target=efi-app-x86_64 -o boot.so bootx64.efi

Use objdump -x to see all the sections available on your boot.so file (we don't have relocations and .bss on this example, so copy of .bss, .rel, .rela and .reloc are not necessary).

Offline JD9999

  • Jr. Member
  • *
  • Posts: 7
  • Country: au
Re: Compiling EFI file from ASM code
« Reply #7 on: August 10, 2021, 11:06:19 PM »
Hey everybody,

I recently found another attempt at a NASM UEFI here: https://github.com/charlesap/nasm-uefi

This one compiles correctly and can run (a little bit) on both QEMU as a .iso and on my USB drive.

From this I have discovered that compiling a .efi is the same method as compiling a .o file.

There are, however, three caveats:
  • The program has an error. It displays "here we go" and then it displays "fail". There are six ways the program can fail, and QEMU doesn't show any text when it runs at all. I guess I would need to write more strings to work out where it fails.
  • It joins two files together using dd. Even though there is a dd for windows which works properly (I'm using the one at http://www.chrysocome.net/), dd is not a windows tool by default, so I would like to find a Windows way of doing it. The two files combining is also a bit confusing. For example, although the shoe-x64.asm file contains the DOS + PE header, the hexdump of both shoe-x64.efi and toe-x64.efi does not contain this DOS header. It's only when the dd command is run, and the files are combined, that the DOS header suddenly appears. I would love to know why this happens.
  • Again, the program does not seem to have a DOS stub at all, until the two files are combined using dd.

I'm much closer to a UEFI OS now, but I don't understand how nasm compiles the efi header without the MZ header present in the hex dump (of the shoe-x64.efi).

If anyone has any pointers or suggestions to help me understand this, I would be very grateful.

Thanks,
Jamie

Offline JD9999

  • Jr. Member
  • *
  • Posts: 7
  • Country: au
Re: Compiling EFI file from ASM code
« Reply #8 on: September 06, 2021, 07:57:39 AM »
I've done it (with much learning from other implementations)!

Have a look at my example code here (https://forum.nasm.us/index.php?topic=2786.0) if you're interested.

Thanks,
Jamie

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Compiling EFI file from ASM code
« Reply #9 on: September 06, 2021, 03:00:37 PM »
Thank you !

Best,
Frank