flat assembler
Message board for the users of flat assembler.
Index
> Windows > [solved] x64 Simple Window never appears |
Author |
|
avidichard 20 Jul 2021, 00:00
Code: format PE64 GUI 6.0 entry sec_start include 'win64w.inc' section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\ user32, 'USER32.DLL' import kernel32,\ GetModuleHandle, 'GetModuleHandleA',\ ExitProcess, 'ExitProcess' import user32,\ RegisterClassEx, 'RegisterClassExA',\ CreateWindowEx, 'CreateWindowExA',\ DefWindowProc, 'DefWindowProcA',\ GetMessage, 'GetMessageA',\ TranslateMessage, 'TranslateMessage',\ DispatchMessage, 'DispatchMessageA',\ ShowWindow, 'ShowWindow',\ PostQuitMessage, 'PostQuitMessage',\ LoadIcon, 'LoadIconA',\ LoadCursor, 'LoadCursorA' section '.data' data readable writeable s_ClassTitle TCHAR "My program's window title", 0 ; Set window title and class name wc WNDCLASSEX ? msg MSG ? l_hWnd dq ? l_hInstance dq ? section '.text' code readable writeable executable sec_start: invoke GetModuleHandle, NULL mov [l_hInstance], rax mov [wc.hInstance], rax mov [wc.cbSize], sizeof.WNDCLASSEX mov [wc.style], CS_HREDRAW or CS_VREDRAW mov [wc.lpfnWndProc], procWnd mov [wc.cbClsExtra], 0 invoke LoadIcon, 0, IDI_APPLICATION mov [wc.hIcon], rax mov [wc.hIconSm], rax invoke LoadCursor, 0, IDC_ARROW mov [wc.hCursor], rax mov [wc.hbrBackground], COLOR_WINDOW+1 mov [wc.lpszMenuName], NULL mov [wc.lpszClassName], s_ClassTitle invoke RegisterClassEx, wc invoke CreateWindowEx, 0, s_ClassTitle, s_ClassTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL mov [l_hWnd], rax invoke ShowWindow, [l_hWnd], SW_SHOW sec_msg_loop: invoke GetMessage, msg, NULL, 0, 0 or rax, rax je sec_end_prog invoke TranslateMessage, msg invoke DispatchMessage, msg jmp sec_msg_loop sec_end_prog: invoke ExitProcess, [msg.wParam] proc procWnd hWnd, msg, wParam, lParam push rbx rsi rdi cmp [msg], WM_DESTROY je sec_destroy_wnd invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] jmp sec_finish sec_destroy_wnd: invoke PostQuitMessage,0 sec_finish: pop rbx rsi rdi ret endp I am just starting use FASM. I chose to go with a very basic Window in x64 NOT x86. So I came up with this code following a similar code from another FASM post I found. When I run it in FASMW, the window never appears, NO error messages show up and no process is present in Windows task manager. The 32 bits version of this code works, I just wanted to make it a 64 bits. I seams to have failed or missed a detail. I supplied the ASM file in the attachments.
|
|||||||||||
20 Jul 2021, 00:00 |
|
bitRAKE 20 Jul 2021, 00:32
The include file 'win64w.inc' does not align the stack. So, when RegisterClassEx uses XMM register instructions (which require 16 byte alignment) an exception is generated. Once this error is resolved the same alignment error takes place within procWnd.
The PROC/ENDP macros support a USES keyword to preserve registers - if you use it then it will align the stack correctly. Example, Code: proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam cmp [msg], WM_DESTROY je sec_destroy_wnd invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] jmp sec_finish sec_destroy_wnd: invoke PostQuitMessage,0 sec_finish: ret endp Additionally, there is the problem of using APIs which expect byte strings, but then including WCHAR support and TCHAR strings. And finally, PROC/ENDP does not store fastcall register parameters in the shadow space. Working program with needed changes becomes: Code: format PE64 GUI 6.0 entry sec_start include 'win64a.inc' section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\ user32, 'USER32.DLL' import kernel32,\ GetModuleHandle, 'GetModuleHandleA',\ ExitProcess, 'ExitProcess' import user32,\ RegisterClassEx, 'RegisterClassExA',\ CreateWindowEx, 'CreateWindowExA',\ DefWindowProc, 'DefWindowProcA',\ GetMessage, 'GetMessageA',\ TranslateMessage, 'TranslateMessage',\ DispatchMessage, 'DispatchMessageA',\ ShowWindow, 'ShowWindow',\ PostQuitMessage, 'PostQuitMessage',\ LoadIcon, 'LoadIconA',\ LoadCursor, 'LoadCursorA' section '.data' data readable writeable s_ClassTitle TCHAR "My program's window title", 0 ; Set window title and class name wc WNDCLASSEX ? msg MSG ? l_hWnd dq ? l_hInstance dq ? section '.text' code readable writeable executable sec_start: push rax invoke GetModuleHandle, NULL mov [l_hInstance], rax mov [wc.hInstance], rax mov [wc.cbSize], sizeof.WNDCLASSEX mov [wc.style], CS_HREDRAW or CS_VREDRAW mov [wc.lpfnWndProc], procWnd mov [wc.cbClsExtra], 0 invoke LoadIcon, 0, IDI_APPLICATION mov [wc.hIcon], rax mov [wc.hIconSm], rax invoke LoadCursor, 0, IDC_ARROW mov [wc.hCursor], rax mov [wc.hbrBackground], COLOR_WINDOW+1 mov [wc.lpszMenuName], NULL mov [wc.lpszClassName], s_ClassTitle invoke RegisterClassEx, wc invoke CreateWindowEx, 0, s_ClassTitle, s_ClassTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL mov [l_hWnd], rax invoke ShowWindow, [l_hWnd], SW_SHOW sec_msg_loop: invoke GetMessage, msg, NULL, 0, 0 or rax, rax je sec_end_prog invoke TranslateMessage, msg invoke DispatchMessage, msg jmp sec_msg_loop sec_end_prog: invoke ExitProcess, [msg.wParam] int3 proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam mov [hWnd],rcx mov [msg],rdx mov [wParam],r8 mov [lParam],r9 cmp [msg], WM_DESTROY je sec_destroy_wnd invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] jmp sec_finish sec_destroy_wnd: invoke PostQuitMessage,0 sec_finish: ret endp Last edited by bitRAKE on 20 Jul 2021, 00:59; edited 1 time in total |
|||
20 Jul 2021, 00:32 |
|
bitRAKE 20 Jul 2021, 01:00
Sorry, I have edited my post extensively.
You'll need to terminate hung application in Task Manager to compile again. |
|||
20 Jul 2021, 01:00 |
|
avidichard 20 Jul 2021, 01:16
It's OK, I now have a window caption that only shows "M" and not the "My program's window title". I changed this line and it works great. I'll be able to finally move on to adding text boxes and other controls.
Code: s_ClassTitle TCHAR "My program's window title", 0 ; Set window title and class name ; BECOMES s_ClassTitle db "My program's window title", 0 ; Set window title and class name I am wondering if I should simply NOT include the win64w.inc file and simply call the constructs and vars myself. I know, I am not in the same programming style if I talk about VB6, but in VB6, we had to define all the variable and const such as MSG, WNDCLASSEX, CS_HREDRAW, etc... So defining those in FASM should not be too different asside from moving them in their proper addresses and space which is not needed in VB6. I could maybe correct the disaligned problem by alligning those myself. Basically, if I can remove the need to using win64w.inc or win64a.inc, that would be great. And as an example like this, all I need is the bare basics to create a window, nothing more and as I can see, the included files include a bunch of unused variables and structs. |
|||
20 Jul 2021, 01:16 |
|
avidichard 20 Jul 2021, 01:23
bitRAKE wrote: Sorry, I have edited my post extensively. It's Okay! I really cannot thank you enough for this. I've been scratching my head and googling for a few days. I'm dumping my old programming languages to program in FASM. It's longer and requires more work but I get to understand MUCH more and I feel less handicaped and more free to do what I want. And using Windows API calls is not new to me so all there is to do is to manually draw and position what's inside the windows instead of relying on predefined noob-proof GUIs. I find ASM a mixture of HTML and VB6 where you have to manually code the position of your elements while relying on windows API calls to display a user interface. The only thing I have to learn is to mov those information using the proper mnemonics and registers. That's the part I need to understand which is still a bit fuzzy for me but I've read so much and went through the FASM guide and Wiki and much more. Thank you very much for your very kind help!!!! |
|||
20 Jul 2021, 01:23 |
|
avidichard 20 Jul 2021, 01:28
WORKING CODE: For those that may land here
Code: format PE64 GUI 6.0 entry sec_start include 'win64w.inc' section '.idata' import data readable writeable library kernel32, 'KERNEL32.DLL',\ user32, 'USER32.DLL' import kernel32,\ GetModuleHandle, 'GetModuleHandleA',\ ExitProcess, 'ExitProcess' import user32,\ RegisterClassEx, 'RegisterClassExA',\ CreateWindowEx, 'CreateWindowExA',\ DefWindowProc, 'DefWindowProcA',\ GetMessage, 'GetMessageA',\ TranslateMessage, 'TranslateMessage',\ DispatchMessage, 'DispatchMessageA',\ ShowWindow, 'ShowWindow',\ PostQuitMessage, 'PostQuitMessage',\ LoadIcon, 'LoadIconA',\ LoadCursor, 'LoadCursorA' section '.data' data readable writeable s_ClassTitle db "My program's window title", 0 ; Set window title and class name wc WNDCLASSEX ? msg MSG ? l_hWnd dq ? l_hInstance dq ? section '.text' code readable writeable executable sec_start: push rax invoke GetModuleHandle, NULL mov [l_hInstance], rax mov [wc.hInstance], rax mov [wc.cbSize], sizeof.WNDCLASSEX mov [wc.style], CS_HREDRAW or CS_VREDRAW mov [wc.lpfnWndProc], procWnd mov [wc.cbClsExtra], 0 invoke LoadIcon, 0, IDI_APPLICATION mov [wc.hIcon], rax mov [wc.hIconSm], rax invoke LoadCursor, 0, IDC_ARROW mov [wc.hCursor], rax mov [wc.hbrBackground], COLOR_WINDOW+1 mov [wc.lpszMenuName], NULL mov [wc.lpszClassName], s_ClassTitle invoke RegisterClassEx, wc invoke CreateWindowEx, 0, s_ClassTitle, s_ClassTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL mov [l_hWnd], rax invoke ShowWindow, [l_hWnd], SW_SHOW sec_msg_loop: invoke GetMessage, msg, NULL, 0, 0 or rax, rax je sec_end_prog invoke TranslateMessage, msg invoke DispatchMessage, msg jmp sec_msg_loop sec_end_prog: invoke ExitProcess, [msg.wParam] proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam mov [hWnd], rcx mov [msg], rdx mov [wParam], r8 mov [lParam], r9 cmp [msg], WM_DESTROY je sec_destroy_wnd invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] jmp sec_finish sec_destroy_wnd: invoke PostQuitMessage,0 sec_finish: ret endp |
|||
20 Jul 2021, 01:28 |
|
bitRAKE 20 Jul 2021, 02:07
avidichard wrote: I am wondering if I should simply NOT include the win64w.inc file and simply call the constructs and vars myself. The debugger is a great way to learn assembler. Instructions can be assembled within and executed at will - while watching the machine state change. "What did that do to the flags or stack?" Whichever way forward you decide will depend on your goals. Having so much control can induce paralysis if you are not careful. Assembly is a lot of control - every bit is at your whim. Every level of abstraction looks out across a sea of change and down an infinite chasm of choice. To set sail or rappel? _________________ ¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup |
|||
20 Jul 2021, 02:07 |
|
avidichard 20 Jul 2021, 07:03
I just realised that the IF, STRUCT and other easy stuff is just part of macros and not actually part of the Assembly language. I thought macros were part of assembly but as I can see, they are NOT. I understand now why we "include" those files now. I thought I could simply ask for a conditional IF with the IF statement but NOOOOO, the macros actually CREATE the if command.
I got your point on paralysis now. Well, I'm actually happy that I have changed my code a bit. Just realised that the LoadCursor and LoadIcon were not necessary to actually run my window. I also chose to start building my own webpage to learn assembly. It's just local for personal use for now until I get AT LEAST something that looks like knowledge. but I'me using this as my color coded code editor I'm used to put images in spoilers but this is how my tool looks like and I love the colors I chose. It also properly indents the code. Well, I guess I can consider this thread closed because I got my solution. Again, a very huge and big thank you for the help. This REALLY got me going!!! A few screenshots of my personal local website about FASM. |
|||
20 Jul 2021, 07:03 |
|
revolution 20 Jul 2021, 07:17
avidichard wrote: I thought I could simply ask for a conditional IF with the IF statement but NOOOOO, the macros actually CREATE the if command. if without any dot, is a native part of the assembler. You can override this behaviour with a macro, but the default macros that come with fasm don't. .if with a leading dot, is a macro. |
|||
20 Jul 2021, 07:17 |
|
avidichard 20 Jul 2021, 07:20
revolution wrote:
Thanks a lot for the precision. I am really enjoying this community. Thank a lot! |
|||
20 Jul 2021, 07:20 |
|
revolution 20 Jul 2021, 07:28
It is the same for struc vs struct. The first is native, the second is a macro.
Also note the letter case. The native version allows mixed case. The default macros only define the lower case version. |
|||
20 Jul 2021, 07:28 |
|
avidichard 21 Jul 2021, 00:01
VERY basic (work in progress) FASM windows tutorial
I just uploaded what I have so far of my FASM tutorial. Of course, this was meant to be for personal use only and to be worked on but at least, it's there somewhere for someone and I can most definately get feedback from others. But I finaly have a working x64 FASM code for a basic window so I now consider my project worth working on now. I also love the modern style of my web page and I want to add more to it. I honestly cannot thank you enough for all your precious comments, solutions and suggestions such as the debugger app that I love. |
|||
21 Jul 2021, 00:01 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.