flat assembler
Message board for the users of flat assembler.
Index
> Windows > The best start to a Windows program Goto page 1, 2 Next |
Author |
|
DimonSoft 30 Apr 2018, 22:47
Mino wrote: (Re)Hello! If we’re talking about HLL compiler (C/C++, I guess?), its main function is not the real entrypoint. In fact, Windows application entry point is generally hidden inside the library and what a programmer sses as main() function is in fact a function called by the library after a lot of initialization and simplification is done. In particular, this function gets several parameters on the stack and thus has to build a complete stack frame. The real entry point (which you can see in FASM example) is just a function with no parameters and thus with no particular calling convention. In fact, you don’t even return from it since this might cause the process hang on certain Windows versions. Mino wrote: 1) What is the main difference between relative and absolute addressing? Well, in general relative addressing is… um… relative. It implies specifying an address relative to some place (say, current value of (E)IP if we talk about jumps). Absolute addressing means that the effective address is directly specified. Mino wrote: 2) What registers should I use as a stack pointer? I always used the general registers (eax, ecx, ...), except one person told me they weren't made for it (he doesn't know FASM), your opinion? ESP is used as a pointer to the top of the stack by all the stack instructions in x86. EBP is generally used as a pointer to a stack frame. I guess, the reason is that it used to imply stack segment when used for addressing. These days the rules are somewhat simpler: most OSes seem to setup all segments the same, SIB addressing may have addressing with EBP go to data segment in some cases. Nothing prevents you from using any general-purpose register to store an address to a place in the stack. Although the two registers mentions above are the most suitable. |
|||
30 Apr 2018, 22:47 |
|
revolution 01 May 2018, 02:32
Moving to Windows forum.
|
|||
01 May 2018, 02:32 |
|
Mino 01 May 2018, 12:00
Ok, thanks for your explanations:)
Actually, I'm writing a compiler (in C++, C and F#) that will use FASM as the target assembler language. I wanted to know what was the best way to compile the high level down, and see what was the best way to start a program, about registries and the entry point. So if you have anything to add about that, I'm listening I don't think I have anything else to add, and sorry for the forum _________________ The best way to predict the future is to invent it. |
|||
01 May 2018, 12:00 |
|
vivik 02 May 2018, 16:40
GetModuleHandle always returns 0x400000. Actually it returns the address of where the exe is loaded to, and I guess it's somewhere in the pe header. There is a neat pe format tutorial here http://win32assembly.programminghorizon.com/tutorials.html . I also have an exe with notes on what is important and what isn't somewhere, can try finding it if you need. Try opening your exe in ollydbg and opening "memory map". Your exe will be on 0x400000 address. Oh, it may be somewhere else if you are on 64bit windows.
DialogBoxParam, i don't know what it is, never seen it before. You probably don't need that. MessageBox is actually either MessageBoxA or MessageBoxW. First is ascii text, second is widechar text. In ascii, one char takes 1 byte, in widechar - 2. Widechar is something like unicode. MessageBoxA 0,"text1","text2",0 usually works fine. You don't need ExitProcess at the end if you have only one thread, you can just use "ret". My program stopped exiting properly once I added directdraw in it, so there were 2 threads. Better have it just in case. I have no idea how to make gui on windows, I'm trying to use directdraw and direct3d directly instead. |
|||
02 May 2018, 16:40 |
|
revolution 02 May 2018, 16:48
vivik wrote: GetModuleHandle always returns 0x400000. Actually it returns the address of where the exe is loaded to, and I guess it's somewhere in the pe header. vivik wrote:
While those two things above might be true for the current versions of Windows, there is nothing that says MS won't change the implementation in a future version. |
|||
02 May 2018, 16:48 |
|
Tomasz Grysztar 02 May 2018, 17:15
revolution wrote:
Still, in case of any doubt it is better to play it safe. As it was rightly pointed out above - it costs practically nothing to call the appropriate function. And the source becomes more readable - a RET instruction may require, unnecessarily in this case, a little bit of mental effort to find out if it is intended to end the thread or just a subroutine. |
|||
02 May 2018, 17:15 |
|
vivik 02 May 2018, 17:28
you guys are boring
By the way, Raymond Chen isn't THAT against using hardcoded module handle: https://blogs.msdn.microsoft.com/oldnewthing/20041025-00/?p=37483 |
|||
02 May 2018, 17:28 |
|
rugxulo 02 May 2018, 17:51
vivik wrote:
I really don't understand all the details here, but I think NT originally was UCS-2. So it wasn't really supporting full Unicode from the start, only a subset of it. I had thought I also heard that modern NT is UTF-16 (same as Java??), but (again) there are so many variations, complications, etc. that I don't honestly know. I haven't done any direct work or learning in that area, so I'm fairly clueless. |
|||
02 May 2018, 17:51 |
|
DimonSoft 02 May 2018, 22:17
revolution wrote: While those two things above might be true for the current versions of Windows, there is nothing that says MS won't change the implementation in a future version. Tomasz Grysztar wrote: While you are generally right here, I would still argue (as I did in the past) that since all threads are equal with regards to Windows API, and since it is documented that returning from a thread "function" is a valid way of terminating it, the return from the "main function" (that is the main thread) may be considered an officially documented and therefore reliable method. But the “main” thread might not be the only one in the process. I remember having problems with RET from WinMain even on WinXP for programs that called GetOpenFileName() function. In Win10 even a simple two-liner fails to terminate this way. Antivirus software, UI customizers and whatever the hell they put into the new Windows release might and does create threads in pretty much every process out there. |
|||
02 May 2018, 22:17 |
|
revolution 03 May 2018, 00:21
DimonSoft wrote: But the “main” thread might not be the only one in the process. I remember having problems with RET from WinMain even on WinXP for programs that called GetOpenFileName() function. In Win10 even a simple two-liner fails to terminate this way. Antivirus software, UI customizers and whatever the hell they put into the new Windows release might and does create threads in pretty much every process out there. |
|||
03 May 2018, 00:21 |
|
vivik 03 May 2018, 04:37
revolution, you have a tendency of warning about "oh no it's scary" without bringing any facts about it.
Though those practices already byte me, most of pouet demos don't work without any kind of messagebox even. |
|||
03 May 2018, 04:37 |
|
revolution 03 May 2018, 05:32
vivik wrote: revolution, you have a tendency of warning about "oh no it's scary" without bringing any facts about it. |
|||
03 May 2018, 05:32 |
|
Tomasz Grysztar 03 May 2018, 07:47
DimonSoft wrote: But the “main” thread might not be the only one in the process. I remember having problems with RET from WinMain even on WinXP for programs that called GetOpenFileName() function. In Win10 even a simple two-liner fails to terminate this way. Antivirus software, UI customizers and whatever the hell they put into the new Windows release might and does create threads in pretty much every process out there. Anyway, my point here was that RET is a valid and documented method of exiting a thread. The differences between ending a thread and ending a process are a different story altogether - you would end up with exactly the same problem if you used ExitThread instead of RET. |
|||
03 May 2018, 07:47 |
|
bitRAKE 03 May 2018, 08:20
When exiting with RETN, I've had applications hang because of other threads - I think related to language features or accessibility? A bunch of extra DLLs were loaded into the process. Never did run it down because ExitProcess fixed it.
|
|||
03 May 2018, 08:20 |
|
DimonSoft 03 May 2018, 11:23
Tomasz Grysztar wrote: Well, if there is another thread that still has some work to do, it would be nicer to let it finish first, wouldn't it? Well, IMHO, the fact that such a thread is created by some third-party software inside my process and is left there behind my back is bad, no matter how useful the thread is for stuff I’m doing. Anyway, I just tried to give another real-life example when the <perfectly valid main function termination since MS-DOS>™ doesn’t do what is generally expected, since vivik started discussing such stuff. vivik wrote: You don't need ExitProcess at the end if you have only one thread, you can just use "ret". My program stopped exiting properly once I added directdraw in it, so there were 2 threads. Better have it just in case. |
|||
03 May 2018, 11:23 |
|
fasmnewbie 07 May 2018, 23:30
Mino wrote: (Re)Hello! The first program is adhering to standard C structure. In C, almost everything is a function, even main function itself. The basic idea behind it -- a function, whatever that is, returns with a RET instruction. This is guaranteed by C, to ensure portability of C's binaries across multiple platforms. C has its own way dealing with program's exit. The return address found at C's TOS points to an area where C hosts its own exit sequence, at least along the MingW toolchain. If you debugged a C program both on Win64 and Linux64, you'll see that they both would produce similar "main" structure at the binary level. You won't see ExitProcess or syscall coming out from main because according to C's design philosophy, main is a function, and a function should use RET, just like any other functions. |
|||
07 May 2018, 23:30 |
|
Furs 07 May 2018, 23:38
fasmnewbie wrote: The first program is adhering to standard C structure. In C, almost everything is a function, even main function itself. The basic idea behind it -- a function, whatever that is, returns with a RET instruction. This is guaranteed by C, to ensure portability of C's binaries across multiple platforms. C has its own way dealing with program's exit. The return address found at C's TOS points to an area where C hosts its own exit sequence, at least along the MingW toolchain. But the C runtime eventually has a "start" (hijacks the entry point) and that's not main. You can think of main as a callback that the C runtime expects you to export. A callback that's just like any other function, yes, but it's definitely not the start of a Windows program. |
|||
07 May 2018, 23:38 |
|
fasmnewbie 07 May 2018, 23:46
C is not a "Windows" program. It's a high-level language that should appear / behave the same across platforms. Whatever happens behind the scene should not be of concern to users / programmers because they are platform-specific by then. It's the same with C's exit sequence. Whatever happens past the RET is ignorable.
|
|||
07 May 2018, 23:46 |
|
fasmnewbie 08 May 2018, 00:05
With BASELIB, one can check what happens behind the scene of C's return sequence. Pay particular attention to the return address. And using "memview" we get to see what exactly C's return sequence is...
Code: ;----------------------------------- ; fasm this.asm ; gcc -m32 this.obj sbase3.dll -o this.exe ;----------------------------------- format MS COFF public _WinMain@16 extrn _stackview extrn _memview section '.data' writeable msg db 'Hello World',0ah,0 section '.text' executable _WinMain@16: push ebp ;C standard prologue mov ebp,esp push 5 ;view main's stack call _stackview mov eax,[esp+4] push eax push 100 call _memview ;what C is hiding at that return address pop ebp ret ; C's standard return Output Code: 00562954 |0022FEA8 00000000 |0022FEA4 00400000 |0022FEA0 00401D6B |0022FE9C ==> C's return address 0022FF18 |0022FE98 5B59F4658D10EC83 |00401D6B| 0|0 ==> C's return sequence at that address B48DC3FC618D5D5E |00401D73| 8|8 74223C0000000026 |00401D7B| 10|16 8403B60F01C3830A |00401D83| 18|24 C0940F223CF275C0 |00401D8B| 20|32 3C86EBC301C0B60F |00401D93| 28|40 E5895595EB897409 |00401D9B| 30|48 FFFFF535E818EC83 |00401DA3| 38|56 E8004013702404C7 |00401DAB| 40|64 9090C3C9FFFFF509 |00401DB3| 48|72 FFFFFF9090909090 |00401DBB| 50|80 00000000401DA0FF |00401DC3| 58|88 FFFFFF00 |00401DCB| 60|96 So the question, is main's RET safe? Yes it is. It is the standard way for C to return control to the OS because it has it's own well-defined return sequence. The examples above is for 32-bit C, using GCC as the linker. |
|||
08 May 2018, 00:05 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.