News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

call & ret

Started by bawrobin, March 27, 2010, 06:51:46 PM

Previous topic - Next topic

jj2007

Interesting. Under Windpws XP (SP2) everything works fine - which is by no means an invitation to declare changing these regs safe...

hutch--

I am still fascinated that after 15 years of the same Intel ABI that there are experienced people who still live under the fantasy that there is a safe way to circumvent it. Use the register preservation convention that it specifies and write safe reliable code in any win32 environment, fail to do so and watch it go BANG somewhere. After having tried for years to get people learning assembler to do this simple stuff the right way the first time, they hear there is an easy way around it and end up writing unreliable code that crashes in some places because it has used registers in illegal ways.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Hutch,

Please share your wisdom with us: Are console apps (not using SetConsoleCtrlHandler) free to use esi edi ebx without preserving, since they have no callback?

donkey

Hi jj2007,

Well, the ABI says this:

Quote from: Windows Programming In Assembly Language - Randall Hydefunctions must preserve the values of certain registers across a function call. If the function needs to modify the value of any of those registers, it must save the register's value and restore it before returning to the caller

If you are the only caller and you do not need them preserved then there is no requirement to preserve them. The ABI is a way to have black box public functions that follow a set of predetermined rules, for private functions (like those Microsoft uses in various DLLs) you need not follow the ABI (and Microsoft doesn't). If the console program has only private functions and they are not called by Windows then there is no need to preserve the registers. Though in reality it is not too much overhead to just preserve them anyway.

So the question is not if they are free to use them but if they are required to preserve them where would they do it ?

Edgar
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

 :bg

JJ,

Is a callback the ONLY interaction with the operating system ?

Internal functions that do not make any OS based calls at all can use registers any way they like AFTER they have been preserved and can do this to any call depth but then that excludes ESP as the stack is supplied by the OS.

Code written without this protection is not reusable in any other context yet there is an easy way to solve the problem, stop ignoring the register preservation convention derived from the Intel ABI and your code NEVER EVER (not even once) crashes on another OS version because of illegal register usage.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: hutch-- on March 28, 2010, 10:01:34 PM
stop ignoring the register preservation convention derived from the Intel ABI

Hutch,
I do not ignore the ABI except when trying hard to make Windows crash. As Edgar said, the overhead is negligible. However, I am a bit fed up of the ambiguous language used here and elsewhere. "only in callbacks", "across functions", "interaction with the OS" etc - the fluffier the formula, the higher the likeliness that the author doesn't really know when exactly preserving is needed, and when it is not needed. So when exactly is it needed in a console app with no callbacks?

qWord

jj,
you can it see as follow: it is the ABI of the compiler M$ used for creating their system DLL's. This compiler assumed that edi,esi and ebx are preserved by called function. So, as long your code is not called from such system libraries (in form of a callback), it doesn't matter what you are doing with registers.
FPU in a trice: SmplMath
It's that simple!

donkey

Hi jj2007,

I think the language is ambiguous or seems to be because it is a difficult thing to explain . Most programmers don't know that the WndProc is actually called by Windows, not your application as is any other procedure that you are required to supply a proc address to Windows for (ie DlgProcs and SortProcs). These are callbacks and because they are called by Windows libraries, you must preserve the registers required by the ABI, if a function is a private function, only called from within your program then there is no need to preserve them. The preservation of registers is of importance only to the caller so if the caller doesn't care then the callee doesn't have to preserve them, with Windows callbacks not preserving them is risky, with private functions there is absolutely no risk now or in any future version of Windows, that would be silly...
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

MichaelW

I think it would depend on how you define "private". If you have a procedure that does not preserve the required registers, and that procedure is called from a callback that does not preserve the registers, then you have a potential problem, even if the procedure and the callback are both in the same program. So basically, any procedure that could be called from a callback should conform to the register preservation conventions.
eschew obfuscation

hutch--

 :bg

JJ,

The simple rule is if you want to write procedures that do not comply with the ABI is to do something this crude.


mov gVar, esp
pushad

; do whatcha wanna do, be watcha wanna beee etc .....

popad
mov esp, gVar


Just don't do anything with the OS in this space.

The endless rule of exception has trashed years of code by learners who see an easy way to write unreliable code by not observing the ABI specs. There are times when I feel like a voice in the wilderness crying out "Do it the right way the first time" and you will never come to grief only to be drowned out by the "you can avoid it here and there but if it crashes on another OS version don't call me, let someone else help them debug their code.  :P

PS: Don't write ANYTHING to the memory pointed to by ESP or it may come back to bite you.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Astro

 :eek  I didn't think that was going to be so controversial!!

Loud and clear here. If you use it, preserve it.  :U

Best regards,
Robin.

hutch--

Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Quote from: donkey on March 28, 2010, 11:06:36 PMMost programmers don't know that the WndProc is actually called by Windows, not your application as is any other procedure that you are required to supply a proc address to Windows for (ie DlgProcs and SortProcs). These are callbacks
Quote from: MichaelW on March 29, 2010, 12:46:11 AM
any procedure that could be called from a callback should conform to the register preservation conventions.
Crystal clear :U

(and it implies that if you use a callback in your console program, you must preserve the regs for Windows)

sinsi

I tend to save every register I use (yes, even ecx and edx, occasionally eax).
I agree with saving ebx/esi/edi, mainly because you can use them in between api calls and trust they aren't changed.
That's the main reason I save regs I use, since I know that e.g. the counter (ecx) will be OK after in a call/loop.

Quote from: hutchPS: Don't write ANYTHING to the memory pointed to by ESP or it may come back to bite you.
Can you give an example? I have used parameters ([esp+4] etc.) as 'local' dword vars with no effects (well, so far).
Light travels faster than sound, that's why some people seem bright until you hear them.

jj2007

Quote from: sinsi on March 29, 2010, 07:00:02 AM
I tend to save every register I use (yes, even ecx and edx, occasionally eax).
In my library code, I use edx and eax as trash or return regs but I save ecx, simply because ecx is a versatile register, especially with loops.

Quote
Can you give an example? I have used parameters ([esp+4] etc.) as 'local' dword vars with no effects (well, so far).

Here is one - the shortest getc ever at 58 bytes. It will not crash, since the stack is your property :bg
push ebx
push eax ; create a slot for TheChar
push eax ; create a slot for TheCount
invoke GetStdHandle, STD_INPUT_HANDLE
xchg eax, ebx ; save hStdIn
push eax ; create a slot for TheMode
invoke GetConsoleMode, ebx, esp ; old mode in slot [esp]
; ebx=hStdIn, new mode allows Ctrl C interrupt:
invoke SetConsoleMode, ebx, ENABLE_PROCESSED_INPUT
lea edx, [esp+4] ; load 2 slot
lea eax, [edx+4] ; addresses
invoke ReadConsole, ebx, eax, 1, edx, 0 ; eax=ptr TheChar, edx=ptr TheCount
push ebx
call SetConsoleMode ; invoke SetConsoleMode, ebx, old mode already in slot [esp]
pop edx ; TheCount
pop eax ; TheChar
pop ebx
movzx eax, al ; get the ASCII code if needed