NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: lostsky25 on August 07, 2020, 08:19:22 PM
-
I have this code:
default REL
extern GetStdHandle
extern WriteFile
extern ExitProcess
section .data
true_msg db 'Yes', 0
true_msg_len equ $-true_msg
section .text
global _main
print_yes:
and rsp, -10h
sub rsp, 020h
mov rcx, -0Bh
call GetStdHandle
mov rcx, rax
mov rdx, true_msg
mov r8, true_msg_len
xor r9, r9
push r9
sub rsp, 20h
call WriteFile
add rsp, 40h
pop rax
ret ;// essentially identical to: pop [register] -> jmp [register]
_main:
mov rcx, 2
cmp rcx, 2
jne false1
call print_yes
false1:
mov rcx, 0 ; RCX - first argument.
call ExitProcess
xor rax, rax
ret
Why I must do something like this:
and rsp, -10h
sub rsp, 020h
Thereafter, I can call 'GetStdHandle', then I want to use 'WriteFile' and I must do this:
sub rsp, 20h
1) Why? How can I find this value for other functions?
Also, I must write this:
add rsp, 40h
pop rax
ret
In the first, I restore the original state of the stack pointer. In the second, 'pop rax' register. If I don't do this, my program will end. RIP will be zero?
2) I always 'pop rax' in other labels/functions?
-
You don't need to play with the stack to build a simple "hello, world" in ASM for Win64:
; Win64 hello.asm
;
; Compiling using NASM and minw64 (linux).
;
; $ nasm -fwin64 -o hello.o hello.asm
; $ x86_64-w64-mingw32-ld -s -e _start -o hello.exe hello.o \
; -L /lib/x86_64-w64-mingw32/ -l:libkernel32.a
;
bits 64
default rel
STD_OUTPUT_HANDLE equ -11
section .rodata
msg: db `hello\r\n`
msg_len equ $ - msg
section .text
; Imported from libkernel32.a
extern __imp_GetStdHandle
extern __imp_WriteConsoleA
extern __imp_ExitProcess
; Entry point
global _start
_start:
mov ecx,STD_OUTPUT_HANDLE
call qword [__imp_GetStdHandle]
mov rcx,rax
lea rdx,[msg]
mov r8d,msg_len
xor r9d,r9d
push r9 ; 5th argument goes to stack.
call qword [__imp_WriteConsoleA] ; WriteConsoleA will cleanup the stack for you!
xor ecx,ecx
jmp qword [__imp_ExitProcess]
Those RSP manipulations are intended for SEH (Structured Exception Handling).
The first AND RSP,-10, and I suspect this is wrong, is intended to align RSP (but it is already aligned by the loader).
-
We're talking about Windows x64 platform here - so no, those RSP manipulations are not intended for SEH (SEH in x64 uses fixed tables and doesn't involve any instructions whatsoever to set up in the actual code).
The x64 calling convention says that you need to allocate a "shadow space" (20h bytes) before calling any function, see e.g. here:
https://retroscience.net/x64-assembly.html#fast-call-procedure-shadow-space-home-space
So that's what that sub rsp, 20h is about.
There is also a requirement for stack alignment - before calling any function, rsp has to be a multiple of 10h. However, that "and" instruction is most likely incorrect - especially if the original value of rsp wasn't stored anywhere, because after the "and" instruction you wouldn't be able to restore it back to the original value. Usually, since you already know the alignment in the current function (from the alignment requirement), you know if you need to subtract 8 bytes or not (to achieve the correct alignment for the called function), so the alignment is rarely done via "and".
As for the second question - in this particular case, it seems to me that the "pop eax" instruction is only used to fix the stack (i.e. to act as a counterpart of that "push r9") - so it should be possible to do only "add rsp, 48h", instead of "add rsp,40h" (and no pop).