flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
AsmGuru62 04 Apr 2025, 00:05
I think after "start:" you need to align the stack to 16 with PUSH RAX, can you try it?
Also, I just tried your code and it does not freeze. I did not change anything. Strange. Last edited by AsmGuru62 on 04 Apr 2025, 00:11; edited 1 time in total |
|||
![]() |
|
bitRAKE 04 Apr 2025, 00:09
The common occurrences of this problem is stack alignment. The ABI requires the shadow-space to be aligned, 0 (mod 16) - the least four bits of the address need to be zero. This is because the OS is using XMM registers and aligned move instructions. You can verify this within the debugger: on entry you'll see the RSP register value is congruent 8 (mod 16).
|
|||
![]() |
|
AsmGuru62 04 Apr 2025, 00:11
I did not align the stack and ran the code as is --- no freeze.
|
|||
![]() |
|
bitRAKE 04 Apr 2025, 00:15
Every build of the OS can use the stack differently.
It's certainly possible another issue accounts for the freeze. |
|||
![]() |
|
Mat-Quasar 04 Apr 2025, 01:05
I think the parameter lpNumberOfBytesWritten cannot be null.
Also, you don't need a null terminating character. |
|||
![]() |
|
bitRAKE 04 Apr 2025, 02:09
Mat-Quasar wrote: I think the parameter lpNumberOfBytesWritten cannot be null. WriteFile Quote: This parameter can be NULL only when the lpOverlapped parameter is not NULL. |
|||
![]() |
|
neeraj9 04 Apr 2025, 04:20
Thanks. I will try the suggestions.
In the meantime, I used chatgpt to generate a simple hello world for fasm on 64 bit and the generated code (see below) froze at the end after printing hello world as well. Code: format PE64 console entry main include 'win64a.inc' section '.text' code readable executable main: sub rsp, 40 ; Shadow space for Win64 calling convention lea rcx, [msg] ; First argument: pointer to string call [printf] ; Call printf function add rsp, 40 ; Restore stack xor ecx, ecx ; Exit code 0 call [ExitProcess] ; Terminate program section '.data' data readable writeable msg db 'Hello, World!', 10, 0 ; String with newline and null terminator section '.idata' import data readable writeable library kernel32, 'kernel32.dll', msvcrt, 'msvcrt.dll' import kernel32, ExitProcess, 'ExitProcess' import msvcrt, printf, 'printf' The following is noticeable in TaskManager, since the binary lingers on a bit for me to capture the info. I am not sure if this is normal or must be investigated. | Process Name | PID | Status | User | CPU | Memory | Arch | Description | |-----------------|-------|----------|------|----|--------|------|------------------| | hello64bit.exe | 80928 | Running | neeraj9 | 00 | 20K | x64 | hello64.exe | | hello64bit.exe | 76456 | Suspended | neeraj9 | 00 | 20K | x64 | Hello64 | |
|||
![]() |
|
Mat-Quasar 04 Apr 2025, 06:48
bitRAKE wrote:
Thank you. I experienced it myself as last time I did a lot of console apps. |
|||
![]() |
|
revolution 04 Apr 2025, 06:54
AsmGuru62 wrote: I think after "start:" you need to align the stack to 16 with PUSH RAX, can you try it? Also note that this code is 32-bit so stack alignment is not needed at all. |
|||
![]() |
|
neeraj9 04 Apr 2025, 08:27
The following code generated by better LLM model from google does a good job of handling the arguments and other things, but the binary still freezes at the end. I turned off my real-time protection for virus and threat protection in windows as well, but that doesnt change a thing.
Code: ; hello.asm (v2 - with stack cleanup before ExitProcess) ; A simple 64-bit Windows console application using FASM ; Prints "Hello, World!" and exits. format PE64 Console ; Target: 64-bit Portable Executable for Console subsystem entry start ; Define the entry point label include 'win64a.inc' ; Include FASM's standard Windows 64-bit definitions ; === Data Section === section '.rdata' data readable message db 'Hello, World!', 0Dh, 0Ah ; The string with CR LF (Windows newline) message_len = $ - message ; Calculate string length at assembly time ; === Code Section === section '.code' code readable executable start: ; Allocate shadow space (32) + local variable space (8 for bytesWritten) ; = 40 bytes. Align to 16 bytes -> 48 bytes. sub rsp, 48 ; Stack layout: ; [rsp+40] - [rsp+47]: bytesWritten (local) ; [rsp+32] - [rsp+39]: 5th argument space (lpOverlapped) ; [rsp+0] - [rsp+31]: Shadow space ; 1. Get StdOut Handle mov ecx, STD_OUTPUT_HANDLE call [GetStdHandle] ; RAX = handle mov rbx, rax ; Save handle in a non-volatile register (optional, just for clarity) ; 2. Write Message mov rcx, rbx ; Arg 1: hFile (saved handle) lea rdx, [message] ; Arg 2: lpBuffer mov r8d, message_len ; Arg 3: nNumberOfBytesToWrite lea r9, [rsp+40] ; Arg 4: lpNumberOfBytesWritten (local var address) mov qword [rsp+32], 0 ; Arg 5: lpOverlapped = NULL (on stack) call [WriteFile] ; 3. Prepare for Exit ; Restore stack pointer (clean up space allocated at the beginning) ; Although ExitProcess won't return, this follows the calling convention ; for the code path leading up to the final call. add rsp, 48 ; 4. Exit Process xor ecx, ecx ; Arg 1: uExitCode = 0 call [ExitProcess] ; Terminate ; === Import Section === section '.idata' import data readable writeable library kernel32, 'KERNEL32.DLL' import kernel32, \ GetStdHandle, 'GetStdHandle', \ WriteFile, 'WriteFile', \ ExitProcess, 'ExitProcess' |
|||
![]() |
|
neeraj9 04 Apr 2025, 08:29
Can one of you come up with a complete example which according to you should work.
In the meantime I am investigating exception visible in x64dbg for all of the 64 bit executable which I posted earlier (even the ones auto-generated by LLM). Quote:
The exception for code generated by google gemini (last one). Quote:
Last edited by neeraj9 on 04 Apr 2025, 08:40; edited 3 times in total |
|||
![]() |
|
revolution 04 Apr 2025, 08:30
Now it is 64-bit code so stack alignment is mandatory. The stack is unaligned.
Code: start: push rbp ; align sub rsp,6*8 ; enough room for 6 qwords |
|||
![]() |
|
neeraj9 04 Apr 2025, 08:43
revolution wrote: Now it is 64-bit code so stack alignment is mandatory. The stack is unaligned. Hey, this worked! Its been a really long time since I did assembly, so took a while. Thanks everyone for awesome support. |
|||
![]() |
|
neeraj9 04 Apr 2025, 08:51
bitRAKE wrote: The common occurrences of this problem is stack alignment. The ABI requires the shadow-space to be aligned, 0 (mod 16) - the least four bits of the address need to be zero. This is because the OS is using XMM registers and aligned move instructions. You can verify this within the debugger: on entry you'll see the RSP register value is congruent 8 (mod 16). It was indeed stack alignment and eventually the following worked for my previous code as well even though `lpNumberOfBytesWritten` was set to NULL. Code:
start:
push rbp
Note: In my specific case (very simple code) it `call [ExitProcess]` which was invoked with misaligned stack (in my case it was aligned to 8-byte and NOT 16-byte as required by win64 calling convention poined out by people here. Leassons: 1. Run your code without stepping through the debugger first and see any exceptions. In my case I stepped through and did not see an exception (not sure why). 2. Read messages carefully and dig deeped into each of the aspects (I missed deep dive into bitRAKE message about stack alignment and revolution mentioned it a couple of times until the last one when I looked at it and fixed it eventually). 3. Dont blindly trust LLM. (every LLMs I asked generated wrong code although ChatGPT reserved space for win64 calling convention but then restored stack just before calling ExitProcess which was wrong). Thanks everyone! ![]() |
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.