flat assembler
Message board for the users of flat assembler.
Index
> Main > UEFI questions Goto page 1, 2, 3 Next |
Author |
|
Trinitek 17 Aug 2016, 22:51
UEFI on x86-64 platforms uses Microsoft's x64 calling convention. You would see the same saving and restoring procedure when entering and leaving a 64-bit function in userspace code on Windows as well.
|
|||
17 Aug 2016, 22:51 |
|
MrFox 18 Aug 2016, 06:56
Thank you Trinitec.
I looked that up, so very interesting thing to read. |
|||
18 Aug 2016, 06:56 |
|
Trinitek 18 Aug 2016, 12:46
Actually, since that's 32-bit code, that would be the cdecl calling convention, but the saving/restoring procedure is the same. Not sure why I didn't catch that.
|
|||
18 Aug 2016, 12:46 |
|
JohnFound 18 Aug 2016, 13:20
ebp is used for comfortable access to the arguments and local variables, both located on the stack.
Of course, you can access these variables using esp directly, but if you push/pop some values in the stack, esp will change and the offset to the variables will change as well. This will make the code much less readable and the risk of bugs increases. In the same time, once, esp is copied to ebp, you can use ebp with constant offset to every local variable (function argument). So, this way, If you don't use local variables or procedure arguments and don't change ebp, there is no need to save it. |
|||
18 Aug 2016, 13:20 |
|
MrFox 19 Aug 2016, 06:34
Umm I've read there about preserving registers, calling conventions, shadow space in the stack... Do I have to adhere to all that within my code as well or does it only refer to external calls and rets (apart from readability issues)?
|
|||
19 Aug 2016, 06:34 |
|
Trinitek 19 Aug 2016, 06:55
MrFox wrote: Umm I've read there about preserving registers, calling conventions, shadow space in the stack... Do I have to adhere to all that within my code as well or does it only refer to external calls and rets (apart from readability issues)? |
|||
19 Aug 2016, 06:55 |
|
MrFox 24 Aug 2016, 18:02
Thanks, Trinitec, that's what I needed to know.
AFAIK, there are not only macros but even special x86 assembly instructions created especially to do such things. Enter and Leave: http://stackoverflow.com/questions/5858996/enter-and-leave-in-assembly does FASM support them? Question #2 I'm wracking my brains around the http://wiki.osdev.org/Uefi.inc and can't figure out why on earth the guy needed all those bells and whistles with redefining data types and structures (see efi.inc titled "The include file" at the middle of the page). Namely, I can't get why he needed all those: Code: ... struc int64 { align 8 . dq ? } ... macro struct name { virtual at 0 name name end virtual } ... struc EFI_TABLE_HEADER { .Signature int64 .Revision int32 .HeaderSize int32 .CRC32 int32 .Reserved int32 } struct EFI_TABLE_HEADER struc EFI_SYSTEM_TABLE { .Hdr EFI_TABLE_HEADER .FirmwareVendor dptr .FirmwareRevision int32 .ConsoleInHandle dptr .ConIn dptr .ConsoleOutHandle dptr .ConOut dptr .StandardErrorHandle dptr .StdErr dptr .RuntimeServices dptr .BootServices dptr .NumberOfTableEntries intn .ConfigurationTable dptr } struct EFI_SYSTEM_TABLE ... why don't we just use: Code: struc EFI_TABLE_HEADER {virtual at 0 ;---------------------- .Signature dq ? .Revision dd ? .HeaderSize dd ? .CRC32 dd ? .Reserved dd ? ;---------------------- end virtual} |
|||
24 Aug 2016, 18:02 |
|
revolution 24 Aug 2016, 18:14
When you put "virtual at 0" inside the struc definition then you won't be able to instantiate the structure into any memory address other than 0. So probably not a good idea unless you know that you never need anything else.
For "enter" and "leave", yes fasm supports them. But most people don't use them because of concerns about performance. But you are free to use them if you wish to. |
|||
24 Aug 2016, 18:14 |
|
MrFox 24 Aug 2016, 18:28
Oh, thanks. What do you mean by performance? Any issues using them?
If I understood that code correctly, that guy uses the structures to only provide offsets, like this: Code: mov edx, dword [rax+EFI_BLOCK_IO_MEDIA.MediaId] or this: Code: clear: mov eax, EFI_SYSTEM_TABLE.ConOut mov ecx, [SystemTable] add ecx, eax mov ecx, [ecx] mov edx, ecx mov eax, SIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen add edx, eax push ecx ; [arg] SystemTable.ConOut mov edx, [edx] call edx add esp, 4 I guess my interpretation of his code will work exactly the same way, won't it? |
|||
24 Aug 2016, 18:28 |
|
revolution 24 Aug 2016, 18:38
By performance, this is how other people view them. Other people think that enter/leave are slow so they avoid them. Sometimes this makes sense, sometimes it doesn't matter. It depends upon what you are doing and where you use them.
If you only ever reference the struc in the way you show then it makes no difference. But you still need to initialise the values by instantiating the struc somewhere, you can't escape this requirement. Merely declaring the struc will not define the value of EFI_TABLE_HEADER.Signature. So you lose some flexibility without any gain in simplicity IMO. |
|||
24 Aug 2016, 18:38 |
|
Tomasz Grysztar 24 Aug 2016, 19:01
revolution wrote: If you only ever reference the struc in the way you show then it makes no difference. But you still need to initialise the values by instantiating the struc somewhere, you can't escape this requirement. Merely declaring the struc will not define the value of EFI_TABLE_HEADER.Signature. So you lose some flexibility without any gain in simplicity IMO. Code: virtual at 0 EFI_TABLE_HEADER: .Signature dq ? .Revision dd ? .HeaderSize dd ? .CRC32 dd ? .Reserved dd ? end virtual |
|||
24 Aug 2016, 19:01 |
|
MrFox 24 Aug 2016, 19:07
Ok, I got it. Thanks.
The thing is, we do not initialize any of these tables or handles. They all already reside in memory when our UEFI app (they call it 'Image') starts and we only need these structures to address offsets within those tables. The app gains System_Table pointer and Loaded_Image handle pointer through stack when it's loaded and all the other references are being made relative to these pointers, 'browsing' the existing tree of structs and handles. That's why I think (as of now, at least) I'll never have to initialize those structures, only to map them on existing addresses. I may be mistaken though as I'm a lil noobie. Would you recommend that I stick to his way of declaration when introducing other structures from UEFI spec (there are tons of them) into that file? --------------- Added: Thanks, Tomasz!!! Simplicity is what I need as these are my 'first steps' at fasm. |
|||
24 Aug 2016, 19:07 |
|
revolution 24 Aug 2016, 19:13
MrFox wrote: Would you recommend that I stick to his way of declaration when introducing other structures from UEFI spec (there are tons of them) into that file? |
|||
24 Aug 2016, 19:13 |
|
MrFox 24 Aug 2016, 19:24
Okay, as of now, I think I'll do what suits me best, i.e. put it as Tomasz suggested, because I hate it when there are pieces in MY code that I don't 100% understand (even if they are technically more correct).
And of course, I'll be 'reading the source' in order to improve my personal understanding of fasm syntax and working principles to get that extra flexibility in the future. Thanks, guys, you rock! |
|||
24 Aug 2016, 19:24 |
|
MrFox 25 Aug 2016, 05:53
Code: virtual at 0 EFI_TABLE_HEADER: .Signature dq ? .Revision dd ? .HeaderSize dd ? .CRC32 dd ? .Reserved dd ? end virtual How can I implement nested structures? I need something like this: Code: struc EFI_SYSTEM_TABLE { .Hdr EFI_TABLE_HEADER .FirmwareVendor dptr .FirmwareRevision int32 .ConsoleInHandle dptr .ConIn dptr .ConsoleOutHandle dptr .ConOut dptr .StandardErrorHandle dptr .StdErr dptr .RuntimeServices dptr .BootServices dptr .NumberOfTableEntries intn .ConfigurationTable dptr } |
|||
25 Aug 2016, 05:53 |
|
Tomasz Grysztar 25 Aug 2016, 07:08
For this you need "struc", because you need to instantiate the same structure in different places. Simplified variant is not your friend in such case.
|
|||
25 Aug 2016, 07:08 |
|
MrFox 25 Aug 2016, 11:16
Thanks!
I have a question regarding programming technique. The task is to browse through the system table and its subtables. They contain values and pointers. This man uses different registers to move along the table and jump to pointers: Code: clear: mov eax, EFI_SYSTEM_TABLE.ConOut mov ecx, [SystemTable] add ecx, eax mov ecx, [ecx] mov edx, ecx mov eax, SIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen add edx, eax push ecx ; [arg] SystemTable.ConOut mov edx, [edx] call edx add esp, 4 ret Why don't we just use one register for all that? Would it be faster or slower? Code: clear: mov eax, [SystemTable] add eax, EFI_SYSTEM_TABLE.ConOut mov eax, [eax] push eax ; [arg] SystemTable.ConOut add eax, SIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen mov eax, [eax] call eax add esp, 4 ret |
|||
25 Aug 2016, 11:16 |
|
MrFox 25 Aug 2016, 11:32
Afterthought: maybe that's done this way to prevent local overheating EAX cpu cirquitry?
|
|||
25 Aug 2016, 11:32 |
|
revolution 26 Aug 2016, 07:51
Don't worry about "overheating" any particular part of the CPU. Use whatever registers you want.
And besides, modern CPUs use register renaming so such a thing isn't possible even if you tried to do it deliberately. |
|||
26 Aug 2016, 07:51 |
|
Goto page 1, 2, 3 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.