Hi!
I'm at my first serious attempt to write X86 assembly code and today, I stumbled on a rather strange problem.

Say this:

void test(int *ptr); //This is the C prototype of the following asm proc

_test:
push ebp
mov ebp, esp

mov eax, 1010
mov ebx, 1010 ;This line causes the issue I'm experiencing
mov edi, ;In link with the use of edi
mov , eax

mov esp, ebp
pop ebp
ret

When this routine is called 2 times in a row, it crashes. When it is called a single time, it doesn't, why? I know ebx is the base register and it is used to address in 16-bit mode but I tought ebx was considered as a general purpose register in 32-bit. I assemble and compile with the latest version of nasm and MinGW.
Posted on 2004-01-09 22:19:06 by PyroMeistar
is this function called from inside a callback? if so then ebx must be preserved as well as esi and edi.
Posted on 2004-01-09 22:32:13 by ENF
No, it is called like this in main()

int main(void)
{
int i;
test(&i);
test(&i);

return 1;
}

But I will try to push/pop ebx & edi as you said. Thanks for your help!
Posted on 2004-01-09 22:45:47 by PyroMeistar
void test(int *ptr); //This is the C prototype of the following asm proc

_test:
push ebp
mov ebp, esp

mov eax, 1010
mov ebx, 1010 ;This line causes the issue I'm experiencing
mov edi, ;In link with the use of edi
mov , eax

mov esp, ebp
pop ebp
ret

i see the that would imply 1 param is passed to the proc, in which case it should be ret 4 instead of ret, looks like stack corruption
Posted on 2004-01-10 00:03:25 by evlncrn8
The C++ compiler requires that called routines preserve EBX, ESI, and EDI.

You can save and restore EBX and EDI with PUSH and POP.
You are not using ESI, so you do not need to do anything special.

By default, C++ and C compilers for Win32 will make the caller (in your case, the C code) remove the arguments, so an ordinary RET is correct.
Posted on 2004-01-10 00:57:06 by tenkey
I think evlncrn8 has got it , he is using which is a parameter. So there was probably something pushed onto the stack before the call:

push 999

call _test

_test:
push ebp
mov ebp, esp
; [ebp+8] = 999
; [ebp+4] = return address
.
.
.
mov esp, ebp
pop ebp
ret 4


The procedure is passed a parameter otherwise would be indeterminate. Obviously test(int *ptr) means that a pointer is being pushed onto the stack so it must be corrected with ret 4.
Posted on 2004-01-10 01:11:03 by donkey
mov ebp, esp
; = 999
; = return address
.
.
.
mov esp, ebp

Thre is no need for mov esp, ebp since ebp allready equals esp. This would only be necercary if there were locals.
Posted on 2004-01-10 01:22:11 by ENF
Agrees with the comments about the stack being corrupted by 4 bytes.
There's no probably about it.

test(&i);
test(&i);

resolves to:

invoke test, addr i
invoke test,addr i

or:

push offset i
call test
push offset i
call test

just change the ret to ret 4
Have a nice day :)
Posted on 2004-01-10 01:57:51 by Homer
Homer,
That would depend on what type of calling convention is the function defined as.

PyroMeistar,
The mostly likely reason is because ebx is used without preservation thereby resulting in a crash (As mentioned by the rest).
Posted on 2004-01-10 04:59:57 by roticv
Thanks for the helpful replies.

I pushed ebx and everything was in order.

The stack isn't corrupted, in fact, I only posted the problematic part of the loop since the complete one is 4 pages of FPU calculations.

Thanks again!
Posted on 2004-01-10 19:33:47 by PyroMeistar