flat assembler
Message board for the users of flat assembler.
Index
> Windows > NOOB Alert! - Trying to understand the basics Goto page 1, 2, 3 Next |
Author |
|
macomics 10 Sep 2021, 10:21
To begin with, I advise you to start by understanding the same program for a 32-bit platform. In the 64-bit code, we added some additional problems.
Now in order. avidichard wrote: ; What does the push actually do??? avidichard wrote: mov [l_hInstance], rax avidichard wrote: mov [l_hWnd], rax avidichard wrote: Then I have the entire label_msg_loop avidichard wrote: Then, there is that procWnd that states "uses rbx rsi rsi". WHY? I really don't get that...Then you have to "mov" with now, rcx, rdx, r8 and r9. Why is it c, d, 8 and 9 all of a sudden I never pushed those? The second part of the question just refers to the problems I mentioned above. Although API functions use the stdcall call type in which all parameters must be passed through the stack in reverse order, but in the 64-bit version, the first 4 parameters are passed to the function through registers (in the appropriate order: rcx, rdx, r8, r9), but a place in the stack is still allocated for them. Your function, using mov commands, simply fills it with the values of these parameters and frees the registers for later use. Based on the above, the cmp [msg], WM_DESTROY command can be changed to cmp rdx, WM_DESTROY. Also taking into account the above, the DefWindowProc call can be performed as follows. Or Code: invoke DefWindowProc, rcx, rdx, r8, r9 Code: sub rsp, 16 call [DefWindowProc] avidichard wrote: And, there is the cmp which I can only presume that it "compares" something. How does the "je" understand that it must be skipped or actually jump to destroy the window? The cmp command <op1>, <op2> compares the values in the operands by performing a subtraction operation (<op1> - <op2>) without changing them (only the flag register changes). The subsequent conditional jump command refers specifically to the value in the flag register. The previous "or" operation was needed for the same purpose (to determine the state of the flag register, but not to change its operands). ADD: A small clarification. If you use the proc/invoke macros, then the type of call suitable for API functions will be organized for your functions written in fasm. But this is not necessary at all. You can decide in what order and how the parameters will be passed to your functions (and also whether they will be extracted from the stack before returning from your function, or whether the calling function should do this). For example, you can pass a single parameter to your function through the rax or r15 register, or pass 6 parameters to the function through the rax, rbx, rcx, r13, r10, rdi registers. But to call other people's functions, you will have to withstand the type of call that was originally designed by the author. |
|||
10 Sep 2021, 10:21 |
|
avidichard 10 Sep 2021, 13:22
What big of a change would it be if I wanted to avoid all macros and do the exact same code using pure ASM? Would the code be that much long? Here's the entire code:
Code: format PE64 GUI 6.0 entry label_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_winTitle db "My program's window title", 0 s_winClass db 'FASMWIN64', 0 wc WNDCLASSEX ? msg MSG ? l_hWnd dq ? l_hInstance dq ? section '.text' code readable writeable executable label_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 mov [wc.lpszClassName], s_WinClass invoke RegisterClassEx, wc invoke CreateWindowEx, 0, s_WinClass, s_WinTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL mov [l_hWnd], rax invoke ShowWindow, [l_hWnd], SW_SHOW label_msg_loop: invoke GetMessage, msg, NULL, 0, 0 or rax, rax je label_end_prog invoke TranslateMessage, msg invoke DispatchMessage, msg jmp label_msg_loop label_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 label_destroy_wnd invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] jmp label_finish label_destroy_wnd: invoke PostQuitMessage,0 label_finish: ret endp |
|||
10 Sep 2021, 13:22 |
|
macomics 10 Sep 2021, 14:08
Code: format PE64 GUI 6.0 entry label_start ; include 'win64w.inc' section '.idata' import data readable writeable ; library kernel32,'KERNEL32.DLL',\ ; user32, 'USER32.DLL' dd RVA kernel32.lookup, 0, 0, RVA kernel32.label, RVA kernel32.address dd RVA user32.lookup, 0, 0, RVA user32.label, RVA user32.address dd 0, 0, 0, 0, 0 kernel32.label db 'KERNEL32.DLL', 0 rb RVA $ and 1 user32.label db 'USER32.DLL', 0 rb RVA $ and 1 ; import kernel32,\ ; GetModuleHandle,'GetModuleHandleA',\ ; ExitProcess,'ExitProcess' kernel32.lookup: dq RVA GetModuleHandle.label dq RVA ExitProcess.label dq 0 kernel32.address: GetModuleHandle dq RVA GetModuleHandle.label ExitProcess dq RVA ExitProcess.label dq 0 GetModuleHandle.label dw 0 db 'GetModuleHandleA', 0 rb RVA $ and 1 ExitProcess.label dw 0 db 'ExitProcess', 0 rb RVA $ and 1 ; import user32,\ ; RegisterClassEx, 'RegisterClassExA',\ ; CreateWindowEx, 'CreateWindowExA',\ ; DefWindowProc, 'DefWindowProcA',\ ; GetMessage, 'GetMessageA',\ ; TranslateMessage, 'TranslateMessage',\ ; DispatchMessage, 'DispatchMessageA',\ ; ShowWindow, 'ShowWindow',\ ; PostQuitMessage, 'PostQuitMessage',\ ; LoadIcon, 'LoadIconA',\ ; LoadCursor, 'LoadCursorA' user32.lookup: dq RVA RegisterClassEx.label dq RVA CreateWindowEx.label dq RVA DefWindowProc.label dq RVA GetMessage.label dq RVA TranslateMessage.label dq RVA DispatchMessage.label dq RVA ShowWindow.label dq RVA PostQuitMessage.label dq RVA LoadIcon.label dq RVA LoadCursor.label dq 0 user32.address: RegisterClassEx dq RVA RegisterClassEx.label CreateWindowEx dq RVA CreateWindowEx.label DefWindowProc dq RVA DefWindowProc.label GetMessage dq RVA GetMessage.label TranslateMessage dq RVA TranslateMessage.label DispatchMessage dq RVA DispatchMessage.label ShowWindow dq RVA ShowWindow.label PostQuitMessage dq RVA PostQuitMessage.label LoadIcon dq RVA LoadIcon.label LoadCursor dq RVA LoadCursor.label dq 0 RegisterClassEx.label dw 0 db 'RegisterClassExA', 0 rb RVA $ and 1 CreateWindowEx.label dw 0 db 'CreateWindowExA', 0 rb RVA $ and 1 DefWindowProc.label dw 0 db 'DefWindowProcA', 0 rb RVA $ and 1 GetMessage.label dw 0 db 'GetMessageA', 0 rb RVA $ and 1 TranslateMessage.label dw 0 db 'TranslateMessage', 0 rb RVA $ and 1 DispatchMessage.label dw 0 db 'DispatchMessageA', 0 rb RVA $ and 1 ShowWindow.label dw 0 db 'ShowWindow', 0 rb RVA $ and 1 PostQuitMessage.label dw 0 db 'PostQuitMessage', 0 rb RVA $ and 1 LoadIcon.label dw 0 db 'LoadIconA', 0 rb RVA $ and 1 LoadCursor.label dw 0 db 'LoadCursorA', 0 rb RVA $ and 1 section '.data' data readable writeable s_winTitle db "My program's window title", 0 s_winClass db 'FASMWIN64', 0 ;wc WNDCLASSEX ? ; struct - macro too wc: wc.cbSize dd ? wc.style dd ? wc.lpfnWndProc dq ? wc.cbClsExtra dd ? wc.cbWndExtra dd ? wc.hInstance dq ? wc.hIcon dq ? wc.hCursor dq ? wc.hbrBackground dq ? wc.lpszMenuName dq ? wc.lpszClassName dq ? wc.hIconSm dq ? wc.Length = $ - wc ; msg MSG ? ; struct - macro too msg: msg.hwnd dq ? msg.message dd ? dd ? msg.wParam dq ? msg.lParam dq ? msg.time dd ? msg.pt.x dd ? msg.pt.y dd ? l_hWnd dq ? l_hInstance dq ? section '.text' code readable writeable executable label_start: xor rcx, rcx ; instead: mov rcx, 0 push rcx ; push rax call [GetModuleHandle] add rsp, 8 mov [l_hInstance], rax mov [wc.hInstance], rax mov [wc.cbSize], wc.Length;sizeof.WNDCLASSEX mov [wc.style], 3; CS_HREDRAW or CS_VREDRAW mov [wc.lpfnWndProc], procWnd mov [wc.cbClsExtra], 0 mov [wc.lpszClassName], s_WinClass lea rcx, [wc] ; instead: mov rcx, wc push rcx call [RegisterClassEx] add rsp, 8 ;invoke CreateWindowEx, 0, s_WinClass, s_WinTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, [l_hInstance], NULL push 0 ; NULL push [l_hInstance] push 0 ; NULL push 0 ; NULL push 480 push 640 push 8000h ; CW_USEDEFAULT push 8000h ; CW_USEDEFAULT mov r9, 000CF0000h; WS_OVERLAPPEDWINDOW lea r8, [s_WinTitle] ; instead: mov r8, s_WinTitle lea rdx, [s_WinClass]; instead: mov rdx, s_WinClass xor rcx, rcx; instead: mov rcx, 0 sub rsp, 32 call [CreateWindowEx] add rsp, 32+64 mov [l_hWnd], rax ;invoke ShowWindow, [l_hWnd], SW_SHOW mov rdx, 5 ; SW_SHOW mov rcx, rax sub rsp, 16 call [ShowWindow] add rsp, 16 label_msg_loop: ;invoke GetMessage, msg, NULL, 0, 0 xor r9, r9 ; instead: mov r9, 0 xor r8, r8 ; instead: mov r8, 0 xor rdx, rdx ; instead: mov rdx, 0 lea rcx, [msg] ; instead: mov rcx, msg sub rsp, 32 call [GetMessage] add rsp, 32 or rax, rax je label_end_prog ;invoke TranslateMessage, msg lea rcx, [msg] ; instead: mov rcx, msg push rcx call [TranslateMessage] add rsp, 8 ;invoke DispatchMessage, msg lea rcx, [msg] ; instead: mov rcx, msg push rcx call [DispatchMessage] add rsp, 8 jmp label_msg_loop label_end_prog: ;invoke ExitProcess, [msg.wParam] mov rcx, [msg.wParam] push rcx call [ExitProcess] add rsp, 8 ;proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam procWnd: push rbp mov rbp, rsp push rbx push rsi push rdi ; instead: rsi mov [rbp+16], rcx mov [rbp+24], rdx mov [rbp+32], r8 mov [rbp+40], r9 cmp dword [rbp+24], 2; WM_DESTROY je label_destroy_wnd ;invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] ; macro generated, redundant ; mov r9, [rbp+40] ; mov r8, [rbp+32] ; mov rdx, [rbp+24] ; mov rcx, [rbp+16] sub rsp, 32 call [DefWindowProc] add rsp, 32 jmp label_finish label_destroy_wnd: ;invoke PostQuitMessage,0 xor rcx, rcx ; instead: mov rcx, 0 push rcx call [PostQuitMessage] add rsp, 8 label_finish: ;ret - macro too lea rsp, [rbp-24] pop rdi ; instead: rsi pop rsi pop rbx pop rbp retn ;endp sorry for the typos, I typed in the browser ADD: it seems that everything has been expanded |
|||
10 Sep 2021, 14:08 |
|
DimonSoft 10 Sep 2021, 17:21
Just a small correction…
macomics wrote:
In fact, it won’t change it since the parameter to RegisterClassEx is marked as [in] in MSDN. The bigger problem is that once one has multiple window classes registered it’s hard to choose which structure should be the source of hInstance value, especially since it is not really related to any of them and is just used as a “namespace” identifier. |
|||
10 Sep 2021, 17:21 |
|
macomics 10 Sep 2021, 18:54
DimonSoft wrote: In fact, it won’t change it since the parameter to RegisterClassEx is marked as [in] in MSDN. The bigger problem is that once one has multiple window classes registered it’s hard to choose which structure should be the source of hInstance value, especially since it is not really related to any of them and is just used as a “namespace” identifier. Precisely because it is marked only as "in", and not "in const", its value is after use and does not necessarily need to be determined. Moreover, I said that it is worth remembering. By the way, there is usually not even a need to save the WNDCLASS(EX) structure. The memory for them is allocated dynamically from the stack and is released immediately after calling the RegisterClass(Ex) function. Code: push 0 push wc_class_name push 0 push 17; COLOR_WINDOWFRAME push 32512 ; IDC_ARROW push 32512 ; IDI_APPLICATION push [l_hInstance] push 0 push l_wndProc push [constStyleAndSize] mov rcx, rsp push rsp call [RegisterClassEx] add rsp, 8+80 https://docs.microsoft.com/en-us/windows/win32/winmsg/using-window-classes Code: BOOL InitApplication(HINSTANCE hinstance) { WNDCLASSEX wcx; // Fill in the window class structure with parameters // that describe the main window. wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes wcx.lpfnWndProc = MainWndProc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = hinstance; // handle to instance wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION); // predefined app. icon wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // predefined arrow wcx.hbrBackground = GetStockObject( WHITE_BRUSH); // white background brush wcx.lpszMenuName = "MainMenu"; // name of menu resource wcx.lpszClassName = "MainWClass"; // name of window class wcx.hIconSm = LoadImage(hinstance, // small class icon MAKEINTRESOURCE(5), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); // Register the window class. return RegisterClassEx(&wcx); } |
|||
10 Sep 2021, 18:54 |
|
avidichard 10 Sep 2021, 22:00
macomics wrote:
Code: dd RVA kernel32.lookup, 0, 0, RVA kernel32.label, RVA kernel32.address ... kernel32.label db 'KERNEL32.DLL', 0 ... kernel32.lookup: So, as I can understand, the "dd RVA kernel32.lookup" is pointing to a label which you named "kernel32.lookup". A label name with a periode "." inside. It got me a bit confused because I usually make a distinction between labels and variables. But this is not an ultra official code so I take it as just an example which I hugely appreciate. so the "kernel32.label" is a variable and you named a lable "kernel32.lookup" if I am reading the code right. Code: mov [wc.style], 3; CS_HREDRAW or CS_VREDRAW Could this have been just defined in the ".data" section? Code: CS_HREDRAW db, 2 CS_VREDRAW db, 1 and then written like this? Code: mov [wc.style], CS_HREDRAW or CS_VREDRAW Code: xor rcx, rcx This code, if I understand properly, simply empties rcx. Code: push rcx call [GetModuleHandle] add rsp, 8 mov [l_hInstance], rax That's something I cannot understand and probably is the hardest point I cannot put a logical explanation to. How can we mov from rax when rax has never been pushed? You pushed rcx but not rax??? Code: xor rcx, rcx ; instead: mov rcx, 0 lea rcx, [wc] ; instead: mov rcx, wc lea r8, [s_WinTitle] ; instead: mov r8, s_WinTitle lea rdx, [s_WinClass]; instead: mov rdx, s_WinClass xor r9, r9 ; instead: mov r9, 0 xor r8, r8 ; instead: mov r8, 0 xor rdx, rdx ; instead: mov rdx, 0 lea rcx, [msg] ; instead: mov rcx, msg Why use the lea and xor instad of the mov? Code: ;proc procWnd uses rbx rsi rsi, hWnd, msg, wParam, lParam procWnd: push rbp mov rbp, rsp push rbx push rsi push rdi ; instead: rsi mov [rbp+16], rcx mov [rbp+24], rdx mov [rbp+32], r8 mov [rbp+40], r9 cmp dword [rbp+24], 2; WM_DESTROY je label_destroy_wnd ;invoke DefWindowProc, [hWnd], [msg], [wParam], [lParam] This part makes my teeth grind a bit because I count 4 parameters but there's only 3 pushes, why? and I don't understand the "mov rpb, rsp" that's the line that puzzles me the most because I don't know what's happenning with that line. It even puzzled me in my original code with the macros. And rcx,rdx, r8 and r9 are never pushed either. |
|||
10 Sep 2021, 22:00 |
|
DimonSoft 10 Sep 2021, 22:04
macomics wrote:
Sorry, I was too focused on the parameter description and forgot to take a look at the function prototype itself which declares the only parameter as a pointer to const, so the question now is who would change the structure contents during the function call if the function itself is not supposed to? macomics wrote: By the way, there is usually not even a need to save the WNDCLASS(EX) structure. The memory for them is allocated dynamically from the stack and is released immediately after calling the RegisterClass(Ex) function. Yep. But my point was that storing and then taking the hInstance value from some WNDCLASSEX is a bad idea from the logical point of view in the first place. |
|||
10 Sep 2021, 22:04 |
|
macomics 10 Sep 2021, 23:01
avidichard wrote: So, as I can understand, the "dd RVA kernel32.lookup" is pointing to a label which you named "kernel32.lookup". A label name with a periode "." inside. It got me a bit confused because I usually make a distinction between labels and variables. But this is not an ultra official code so I take it as just an example which I hugely appreciate. so the "kernel32.label" is a variable and you named a lable "kernel32.lookup" if I am reading the code right. Code: ParentName: .ChildName0: .ChildName1 db "Hello", 0 .ChildName2 = 5 .ChildName3 dq 0xFFFF0000FFFF0000 repeat .ChildName2 nop end repeat mov rax, [.ChildName3] lea rcx, [.ChildName1] call .ChildName0 NewParentName: repeat ParentName.ChildName2 nop end repeat mov rax, [ParentName.ChildName3] lea rcx, [ParentName.ChildName1] call ParentName.ChildName0 avidichard wrote:
http://flatassembler.net/docs.php?article=manual avidichard wrote:
avidichard wrote: Why use the lea and xor instad of the mov? Code: relativeValue equ qword [rcx+8] MyFunction: virtual at rbp+16 .argValue0 dq ? .argValue1 dq ? .argString dq ? end virtual mov rcx, [.argValue0] lea rax, relativeValue lea rdx, [.argValue1] mov rsi, [.argString] avidichard wrote:
1. An assembly language function can start with any label in the code section. What happens after calling this function will be the body of the function. 2. Designing the design of the function falls on the shoulders of its author. 2.1) The placement of function parameters can be in general or special purpose registers, stack or global variables. 2.1.a: The placement of function parameters in global variables does not carry any design features and is characterized only by the use of absolute addresses in the function body. 2.1.b: When using general/special purpose registers, no design changes are also required, but you will have to watch for possible overwriting of the input parameters of the function before/after calling the subfunctions. 2.1.c: When using a stack to pass parameters to a function, a temporary structure is formed on its top with a certain set of variables prepared by the function that called it to work with them in the body of your function. You can work with such a structure in 64-bit addressing both with respect to the rsp register (but then you will have to control the stack filling), but also with respect to any other register in which the stack address will be fixed at the time of entering the function (in the IA-64 architecture, the rbp register is provided for fixing the stack).In order for the calling function to use it for the same purpose, its value must be saved and restored at the entering and leaving of your function. Code: sample1: push rbp ; saving the value when entering mov rbp, rsp ; fixing the stack pointer ; now all parameters get fixed relative addresses anywhere in the function ; qword [rbp + 0] = old rbp ; qword [rbp + 8] = return address ; qword [rbp + 16] = arg0 ; qword [rbp + 24] = arg1 ; . . . <body> mov rsp, rbp ; return the stack pointer to the position before entering the function pop rbp ; restoring the value when leaving . . . Last edited by macomics on 11 Sep 2021, 01:05; edited 2 times in total |
|||
10 Sep 2021, 23:01 |
|
avidichard 10 Sep 2021, 23:31
macomics wrote: No. These values must be defined anywhere in the program (even outside the data section) as symbolic or numeric constants. Only then will their similar application become possible. For more information, see the manual: http://flatassembler.net/docs.php?article=manual So, if I understand properly, I would set: CS_HREDRAW db, 2 CS_VREDRAW db, 1 BEFORE the ".idata" section. so this would make "mov [wc.style], CS_HREDRAW or CS_VREDRAW" now possible? I also saw that you did ".ChildName0:" was the colon ":" volantary? Because if I'd follow your example, "ParentName:" is, in my dictionary, a lable because it ends with a ":". Now, what you are saying is that if you add "." on any variables under like all of your ChildNames, this means that ParentName is no longer a label but a structure of some sort. And if you really intended to have a ":" after ChildName0, then ChildName1 is linked to ChildName0 where ChildName1,2 and 3 are now accessible like this: "ParentName.ChildName0.ChildName1" and "ParentName.ChildName1" is not accessible. macomics wrote: The value placed by the push rax command does not matter. The main point of this command is to reserve memory in the stack for the parameter of this function. The value itself must be placed in the rcx register. I just don't see much difference between the push rax and push rcx commands in this case. So, I don't know if I get this right. BUT, if I use "push rcx" this would automatically reserve the space for rax and rbx? If I "push rdx" this would automatically reserve rax, rbx and rcx? macomics wrote: A relative address, not an absolute address, can be defined behind the name. In order not to run into these rakes every time, I have already developed the habit of using lea to load addresses. So I understand that both do the job "mov" and "lea" but one should know to use proper programming practices for the right situations and not just be lazy using mov all the time just because it works? |
|||
10 Sep 2021, 23:31 |
|
macomics 10 Sep 2021, 23:36
2.2) In addition to the parameters of the function, local (temporary) variables can be defined that will be available before exiting this function. To organize access to them and their placement, the same technique is used that describes the parameters passed through the stack.
Code: sample2: .local_variables_bytes = 128 push rbp mov rbp, rsp sub rsp, .local_variables_bytes ; now all variables get fixed relative addresses anywhere in the function ; qword [rbp-8] = var0 ; qword [rbp-16] = var1 ; qword [rbp-24] = var2 ; qword [rbp-32] = var3 ; . . . mov rsp, rbp ; now this command finds its main meaning pop rbp . . . 2.3) When using parameters passed through the stack, it is also necessary to determine the order of the parameters in the stack (the C language uses the reverse enumeration of parameters, but Pascal preferred direct enumeration) and the mechanism for its release from them. If in the case of local variables, the function should always release the memory occupied by them, then with parameters it is another matter. Depending on the type of call, parameters may be pushed off the stack when returning from your function, or each call to your function must be supplemented with a stack balancing command: Code: sample3: .args_bytes_count = 8 . . . retn .args_bytes_count sample4: .args_bytes_count = 16 . . . retn callerFunc: call sample4 add rsp, sample4.args_bytes_count call sample3 call sample4 add rsp, sample4.args_bytes_count 2.4) In the 64-bit (LONG) mode, only near function calls are available for the user program to form, but other types of calls are also possible in other modes (call far 0x0023:0x00401000) 3. As I have already said, it is accepted in Windows OS that it is necessary to restore the values of the rbx, rbp, rsi, rdi registers after returning from any callback function. Therefore, I save and restore the values of these registers (although I just expanded the code that the macros will generate, and it says: uses ebx, rsi, rdi) 4. Then there is a vestige of the problem, which I also already mentioned warning you in the first post. In the 64-bit version of Windows, it is customary to place the values of the first 4 parameters of the function in registers, but to save these parameters, the calling function allocates a block of memory in the stack (although it does not add the values of these parameters to it, it is strange why). With the complication of the program, the window function will grow abundantly and in order not to erase these values at the very beginning, we add them to the memory allocated for them. 5. Again, I was just unwrapping the macro code and therefore used the value that was stored on the stack. But nothing prevents you from writing the edx register instead of dword [rbp+24] |
|||
10 Sep 2021, 23:36 |
|
macomics 11 Sep 2021, 00:00
avidichard wrote:
avidichard wrote:
Code: Parent.Name: ; global name .Child.Name: ; local name ("Parent.Name.Child.Name") .Child.Name1 db 1 ; local name ("Parent.Name.Child.Name1" as byte value = 0x01) call .Child.Name ; call Parent.Name.Child.Name .function db 195 ; local name (void function: Parent.Name.function as retn ) New.Parent.Name: ; A new global name, after which all calls to the previous local names require the mandatory indication of the preceding global name .Child.Name: ; local name ("New.Parent.Name.Child.Name") call Parent.Name.Child.Name avidichard wrote:
avidichard wrote: So I understand that both do the job "mov" and "lea" but one should know to use proper programming practices for the right situations and not just be lazy using mov all the time just because it works? Code: string db "abracadabra . . .", 0 lea rdi, [string] or rcx, -1 xor rax, rax mov rdx, rdi repne scas byte [rdi] lea rcx, [rdi-1] mov rdi, rdx sub rcx, rdx mov al, ' ' repne scas byte [rdi] jnz no_space lea rsi, [rdi-1] . . . no_space: . . . DimonSoft wrote: Sorry, I was too focused on the parameter description and forgot to take a look at the function prototype itself which declares the only parameter as a pointer to const, so the question now is who would change the structure contents during the function call if the function itself is not supposed to? It depends on the implementation of the API functions and the presence of an interception function. DimonSoft wrote: Yep. But my point was that storing and then taking the hInstance value from some WNDCLASSEX is a bad idea from the logical point of view in the first place. And why store it at all, when it is possible to call GetModuleHandle(NULL) {GetWindowLong(hWnd,GWL_HINSTANCE) / GetClassLong(hWnd, GCL_HINSTANCE) } at any time. And WNDCLASS(EX) can be read by calling GetClassInfo(Ex). Last edited by macomics on 11 Sep 2021, 01:07; edited 1 time in total |
|||
11 Sep 2021, 00:00 |
|
Overclick 11 Sep 2021, 16:05
Am I alone to see you guys don't understand each other? You complicate everything you talking about.
Just use it like that: CS_HREDRAW = 2 CS_VREDRAW = 1 And don't push first four parameters to stack in 64bit mode winapi. Functions need them in rcx,rdx,r8,r9. Use Invoke to be sure the args passed correctly. Threre is few rules it uses for integer, float and rest of params. The result (usualy) returns in rax. |
|||
11 Sep 2021, 16:05 |
|
macomics 11 Sep 2021, 16:26
Code: macro invoke proc,[arg] { common fastcall [proc],arg } macro fastcall proc,[arg] { common local stackspace,argscount,counter if argscount < 4 stackspace = 4*8 else if argscount and 1 stackspace = (argscount+1)*8 else stackspace = argscount*8 end if counter = 0 if stackspace if defined current@frame if current@frame<stackspace current@frame = stackspace end if else if stackspace sub rsp,stackspace end if end if end if This I still reserve a little in the stack. in general, invoke always reserves 32 bytes in the stack. Even when the arguments are 0. |
|||
11 Sep 2021, 16:26 |
|
Overclick 11 Sep 2021, 17:02
Quote:
|
||||||||||
11 Sep 2021, 17:02 |
|
macomics 11 Sep 2021, 17:11
[quote="Overclick"] The function being called is not required to save input parameters passed through the registers into the stack but reserving space in the stack allows to do this if necessary.
|
|||
11 Sep 2021, 17:11 |
|
Overclick 11 Sep 2021, 17:24
Microsoft decided to use it like that. Seems it was needed for 32 to 64 old-code migration.
|
|||
11 Sep 2021, 17:24 |
|
macomics 11 Sep 2021, 17:30
No automatic compiler will generate code to save a non-existent parameter in the buffer for parameters, even if it needs to release the register rcx, rdx, r8, r9. But some self-made function from a craftsman can easily create assembly commands like this.
|
|||
11 Sep 2021, 17:30 |
|
Overclick 11 Sep 2021, 17:49
Not like that. They reserved stack to call old 32bit winapi when you don't even know what's happening ))
I don't believe they recompilled tons of code to 64bit. Not that fast at days WinXP-64 become. |
|||
11 Sep 2021, 17:49 |
|
macomics 11 Sep 2021, 17:57
Of course, I understand that you are in a smartphone, but the latest news: Microsoft has already refused even to support Windows 7/8. WinXP-64-the last decade.
|
|||
11 Sep 2021, 17:57 |
|
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.