flat assembler
Message board for the users of flat assembler.

Index > OS Construction > Use UEFI Graphics Output Protocol

Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next
Author
Thread Post new topic Reply to topic
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 17 Apr 2020, 15:08
Shadow space is always needed that is why I put ENTER instruction at the beginning: it aligns the stack MOD16, and also reserves local space for shadow and additional parameters -- all in one instruction. If one is not playing with RSP (remains constant) then nothing further needs to be done at this call level.

https://board.flatassembler.net/topic.php?t=7119
Post 17 Apr 2020, 15:08
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 16:32
But i don't understand. Why some UEFI fonction work without this stack ? For example, when i call UEFI function to ClearScreen, no problem without any stack.
And why do you change stack value into this address (for example)?
Code:
mov qword[rsp+8*5],EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL    

In this link provided by you : https://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention, it's written about shadow space:
Quote:
it is the caller's responsibility to allocate 32 bytes of "shadow space" on the stack right before calling the function

But if i calculate good, 32 bytes is for 64bits x4 ? But when you pass rsp+8*5, what is the connection ???

I'm lost.
And if you need to initialize stack, why i don't seen in your code any SS value asignment ?

And in last, why there many UEFI calling convention, for example Sys V, Microsoft ... etc, UEFI isn't unified firmware .... ? If i remember good, UEFI boot from PE executable, no other file type ... how Unix can call differently UEFI fonction ?

Some points are very obscure
Post 17 Apr 2020, 16:32
View user's profile Send private message Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 17 Apr 2020, 17:15
It's true that UEFI uses PE file format, but there is no OS. So, much of the OS-specific PE requirements don't apply. For example, there is no sub-system or exception handling. This is why we need to fall back to the UEFI spec in all cases.

I know where RSP is at all times in my code. Wink I do reserve shadow space at the start of each level of code and know it is there throughout:
Code:
Level0:
        enter 1024,0 ; shadow space

        mov [rsp+8*5],$CAFE
        call Level1
        call Level2
        call Level3
        call Level4
;...
        leave
        retn

Level1:
        enter 32,0 ; local shadow

        call Level2

        leave
        retn

Level2:
        enter 32,0 ; local shadow

        call Level1

        leave
        retn

; etc...    
...do you see how flexible this pattern is? Initialization is optional in the case where parameters are strictly output - why just set a value to have it changed? I re-use parameter space as needed without playing with RSP frivolously.
Quote:
on the stack right before calling the function
... targets Windows table-based exception handling semantics, and doesn't entirely apply to UEFI.

It is completely possible that some UEFI functions do not use the shadow space, but we cannot rely on that being the case on all firmware. Unix needs to support different calling conventions in their compilers. I don't care about any of those politics that get in the way of my programming. On Linux, I use the red zone and different registers - whatever the environment specifies.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 17 Apr 2020, 17:15
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 17:35
Okay, now i understand for ENTER call just one time. But i don't understand your calculation. why rsp + 8*5 ? Dont you store qword into the stack ?
Post 17 Apr 2020, 17:35
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 18:05
Fulgurance wrote:
But i don't understand. Why some UEFI fonction work without this stack ?
Relying on undocumented behaviour is a path to failure. It might work on your system. It might fail on someone else's system. It might be clobbering your stack and you just don't know it yet, until you put something into a sub-function and then it suddenly fails.
Post 17 Apr 2020, 18:05
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 18:10
Okay... And about my previous question ?

Quote:
Okay, now i understand for ENTER call just one time. But i don't understand your calculation. why rsp + 8*5 ? Dont you store qword into the stack ?


And why when i try to call BootServices LocateHandle function, i have return of unknown error code ? I haven't 0,1 or 2 ...
Post 17 Apr 2020, 18:10
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 18:16
All functions are entered with the stack at 16n+8 because the call will push the return address of 8 bytes. So you need to push one more 8 byte value to align it to 16n+0. And from there you always adjust even multiples of 8 bytes to keep the stack at 16n+0.

This is why your EFIBootServicesStatusCode code is incorrect. It doesn't align the stack to 16n+0 and it doesn't allocate any shadow space when it calls external functions. When your code doesn't comply with the spec then you can't guarantee it will work.

Slow down. Test each piece one-by-one. You have many wheels turning all at once, and when one or more fail you don't know which are working and which are failing.
Post 17 Apr 2020, 18:16
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 17 Apr 2020, 18:40
Fulgurance wrote:
But i don't understand your calculation. why rsp + 8*5 ? Dont you store qword into the stack ?
[rsp+8*5] would be the address of the sixth parameter when making a call in this ABI. RSP is the stack pointer. So, this address is on the stack. QWORDs are eight bytes. Where is the confusion exactly? 8*5 is the offset and not a size designation.

[rsp+8*0] ; shadow space for parm one (volitile)
[rsp+8*1] ; shadow space for parm two (volitile)
[rsp+8*2] ; shadow space for parm three (volitile)
[rsp+8*3] ; shadow space for parm four (volitile)
[rsp+8*4] ; param five must be stored here
[rsp+8*5] ; param six must be stored here

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 17 Apr 2020, 18:40
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 18:56
Yes,it's an address, it's true. I have forgotten...

But i don't understand: if you have parameter on the stack at RSP+ 8*5 address, the next parameter piushed into stack as 64 bits size, the next offset is 64 bits further on ?

For example, when i make that simple code, the second label have this address 64 bits further on. It's not the same thing into stack ?

Code:
label1:
dq ?

label2:
dq ?
    


EDIT: Rolling Eyes I think i have forgotten address are calculate in bytes omg... not bits
Post 17 Apr 2020, 18:56
View user's profile Send private message Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 20:22
For example, just that, is it correct ?

Code:
enter 24,0
and spl,0xF0
mov rcx,[rdx+EFISystemTable.BootServices]
mov rax,[rcx+EFIBootServices.LocateProtocol]
mov rdx,GUID.EFIGraphicsOutputProtocol
xor r8,r8
mov r9,Interface.EFIGraphicsOutputProtocol
call rax
leave    


I prepare shadow stack for 3 parameters, 3 x 8 bytes = 24, with enter 24,0, is it okay ?
I ensure stack alignment with and spl,0xF0, is it right ?
Next, i pass parameters and call function.
I release stack after with leave instruction.
Is it okay ?
Post 17 Apr 2020, 20:22
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 20:29
Fulgurance wrote:
For example, just that, is it correct ?

Code:
enter 24,0
and spl,0xF0
mov rcx,[rdx+EFISystemTable.BootServices]
mov rax,[rcx+EFIBootServices.LocateProtocol]
mov rdx,GUID.EFIGraphicsOutputProtocol
xor r8,r8
mov r9,Interface.EFIGraphicsOutputProtocol
call rax
leave    


I prepare shadow stack for 3 parameters, 3 x 8 bytes = 24, with enter 24,0, is it okay ?
I ensure stack alignment with and spl,0xF0, is it right ?
Next, i pass parameters and call function.
I release stack after with leave instruction.
Is it okay ?
No. This is not correct.

Follow the spec. When a function starts you need to align the stack first, usually with a "push rbp", but can also be "sub rsp,8". Do this once only at function entry, and reverse it upon function exit.

Using "and rsp,-0x10" can be a problem if you ever want to do a "ret" later, I suggest not to use "and rsp,-0x10", it is a bad habit.

Allocating 24 bytes is wrong. Always allocate in multiples of 16. Always allocate after stack alignment is done at function entry. Always allocate at least 32 bytes of shadow space for the callee to use, and allocate more when you have more than four parameters. I suggest not to use enter or leave, they have hidden usage of registers and make the code more opaque IMO. Instead use explicit registers and instructions that clearly show what is happening.

Follow the spec. You are getting yourself in trouble by trying to do different things.
Post 17 Apr 2020, 20:29
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 20:57
Thanks, your explanation is simple. Some of yours examples code are difficult for me, many instructions used is for me unknow. I know just base instruction, but not SSE or other ...

I must stay simple.

I have trying to correct my previous code, is this okay ?

Code:
mov rbp,rsp
add rsp,0x20
sub rsp,0x8
mov rcx,[rdx+EFISystemTable.BootServices]
mov rax,[rcx+EFIBootServices.LocateProtocol]
mov rdx,GUID.EFIGraphicsOutputProtocol
xor r8,r8
mov r9,Interface.EFIGraphicsOutputProtocol
call rax
mov rsp,rbp    


(i save rsp pointer, i think it's good idea)
Post 17 Apr 2020, 20:57
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 21:08
You didn't give enough context. Is that an entire function?

Assuming it is then I suggest something like this:
Code:
my_function:
push rbp ;we must save this for the caller, and this also aligns the stack
;mov rbp,rsp ;we don't need this here, but if you have entry parameters then this can be useful
sub rsp,0x20 ;minimum requirement, use more if you have more than 4 parameters
mov rcx,[rdx+EFISystemTable.BootServices] ;rcx = first parameter to callee
mov rax,[rcx+EFIBootServices.LocateProtocol]
mov rdx,GUID.EFIGraphicsOutputProtocol ;rdx = second parameter to callee
xor r8,r8 ;r8 = third parameter to callee
mov r9,Interface.EFIGraphicsOutputProtocol ;r9 = fourth parameter to callee
call rax
add rsp,0x20 ;reverse of what we allocated above
pop rbp ;now the top of stack is the return address
ret    
Post 17 Apr 2020, 21:08
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 21:32
Why you push RBP, i don't understand that... Is it mandatory for calling convention into UEFI ? What do you call the "return address" ?
If programmer use RBP, is it not just to save RSP ? Don't you have initialized any value at RBP, no ?

Just look this if you need my code context (i have applied your example):

Code:
format pe64 efi
entry Main

section '.text' code readable executable

Main:
mov [SystemTable],rdx

push rbp
sub rsp,0x20
mov rcx,[rdx+EFISystemTable.BootServices]
mov rax,[rcx+EFIBootServices.LocateProtocol]
mov rdx,GUID.EFIGraphicsOutputProtocol
xor r8,r8
mov r9,Interface.EFIGraphicsOutputProtocol
call rax
add rsp,0x20
pop rbp

mov rdx,[SystemTable]

jmp $

include "EFIBase/GUID.fasm"
include "EFIBase/Interface.fasm"
include "EFIBase/EFIDataTypes.fasm"
include "EFIStatusCode/EFIBootServicesStatusCode.fasm"
include "EFITableHeader/EFITableHeader.fasm"
include "EFISystemTable/EFISystemTable.fasm"
include "EFIBootServices/EFIBootServices.fasm"
include "EFIBootServices/IndexTables/EFILocateSearchType.fasm"
include "EFISimpleTextOutputProtocol/EFISimpleTextOutputProtocol.fasm"
include "EFIGraphicsOutputProtocol/EFIGraphicsOutputProtocol.fasm"
include "EFIGraphicsOutputProtocol/IndexTables/EFIGraphicsOutputBltOperation.fasm"

section '.data' data readable writable executable

SystemTable:    dq ?    
Post 17 Apr 2020, 21:32
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 21:45
I used push rbp for three purposes.

The first is to align the stack because the caller always gives us a stack align to 16n+8, so we have to fix it to 16n+0.

The second is that now we can use rbp for our own purposes. We have to return a valid value in rbp to the caller, so saving it means we can now use it and restore it later when we do a ret.

The third is to give access to any caller parameters on the stack.

It isn't always necessary to save rbp if you never use it, but if you don't save it then you need an alternative instruction to align the stack. "sub rsp,8" will also do that. It encodes to more bytes if that is an issue to you. But you need something to align the stack. You can't avoid it.
Post 17 Apr 2020, 21:45
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 21:48
BTW: Are you sure the SystemTable parameter is in RDX?

RDX is the second parameter. What is in RCX?
Post 17 Apr 2020, 21:48
View user's profile Send private message Visit poster's website Reply with quote
Fulgurance



Joined: 27 Nov 2017
Posts: 276
Fulgurance 17 Apr 2020, 22:16
How can you sure stack is aligned when you push RBP, it's that i understand ...
And you say 16n+8, what is n ? What do you mean ?

Quote:

BTW: Are you sure the SystemTable parameter is in RDX?

When UEFI start, isn't RDX pointer to SystemTable ?
RCX must contain first parameter ? Is it that ??? :O

I'm totally lost o_o
Post 17 Apr 2020, 22:16
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 17 Apr 2020, 23:01
The calling standard guarantees that the stack is at 16n+8 upon entry to your code. "n" is any number so multiplying by 16 means the lowest four bits are zero. So a single push will put the stack at 16n+0 and your stack is now aligned.
Post 17 Apr 2020, 23:01
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 18 Apr 2020, 06:25
RCX is the ImageHandle
RDX is the SystemTable

Signed images can use their handle to access protocols if SecureBoot is enabled.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 18 Apr 2020, 06:25
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20306
Location: In your JS exploiting you and your system
revolution 18 Apr 2020, 06:59
So have we verified that setting rcx = [rdx+EFISystemTable.BootServices] as the first parameter for the call is correct? It seems to be redundant if it is.
Post 18 Apr 2020, 06:59
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page Previous  1, 2, 3, 4, 5, 6, 7  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.