问题
I'm trying to sent DWORD variable into function as pointer paramater
variable1 dd 1
...
push [variable1] ; push variable adress
call _InitPoiner
...
_InitPoiner:
;
push ebp
mov ebp, esp
;
lea eax, [ebp+8] ; load address
mov dword [eax], 10 ; move value 10 into that address
pop ebp
ret
...
push [variable1]
push sdigit ; where sdigit db '%d', 0x0D, 0x0A, 0
call [printf]
but variable1 is 1, not 11 , why?
回答1:
You are making sure that you pop your vars when done?
Looking at your example, I see no way that the variable could ever be 11. It starts as 1 at the dd
assignment, then if your math in the lea is correct, it would then be 10. If you were to step this through a debugger, you could check if your lea / mov
combo is working right. Either way, I would expect 1 or 10, not 11.
Maybe you meant to add
instead of mov
?
回答2:
The main problem is that you are not pushing the address of variable1
onto the stack when you do push [variable1]
. That pushes the 32-bit value stored at variable1 which happens to be the value of 1. To push the address you would use push variable1
without the brackets.
When pushing values onto the stack before a call you need to restore the stack after the call.
LEA wasn't getting the address stored on the stack but getting the address of the stack location where the address should have been stored. I think you were looking for something like:
format ELF
extrn printf
public main
section '.text' executable
main:
push variable1 ; push address of variable
call _InitPointer
add esp, 4 ; We pushed 4 bytes before calling function
; restore the stack by adding 4
push [variable1] ; Push the value at address variable1
push sdigit ; Format specifier for printf
call printf
add esp, 8 ; We pushed 8 bytes of data for call
; restore the stack by adding 8
ret
_InitPointer:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; There is an address at [ebp+8] that
; was pushed as the 1st parameter. Put the
; address in EAX
add dword [eax], 10 ; Add the value 10 to the DWORD value that is at
; address in EAX
pop ebp
ret
section '.data' writeable
variable1 dd 1
sdigit db '%d', 0x0D, 0x0A, 0
You didn't mention the platform you are on as you didn't supply a minimal complete verifiable example. The code above could be tested on Linux with:
fasm test.asm
gcc -o test -m32 test.o
When run you should get:
11
The equivalent C code would look like:
#include <stdio.h>
void _InitPointer (int *ptr)
{
*ptr += 10;
return;
}
int variable1 = 1;
int main()
{
_InitPointer (&variable1);
printf ("%d\n", variable1);
return 0;
}
Note: If on modern versions of Linux, 32-bit programs follow System V i386 ABI that requires the stack be 16-byte (or 32-byte) aligned at the point of a function call. I didn't do that in the code above to keep it simplified but it should be taken into account. I'm unsure if you are on Linux or Windows. Your question doesn't say.
32-bit Windows Version
format PE console 4.0
include 'win32a.inc'
main:
push variable1 ; push address of variable
call _InitPointer
add esp, 4 ; We pushed 4 bytes before calling function
; restore the stack by adding 4
push [variable1] ; Push the value at address variable1
push sdigit ; Format specifier for printf
call [printf]
add esp, 8 ; We pushed 8 bytes of data for call
; restore the stack by adding 8
push 0 ; Exit with return value 0
call [ExitProcess]
_InitPointer:
push ebp
mov ebp, esp
mov eax, [ebp+8] ; There is an address at [ebp+8] that
; was pushed as the 1st parameter. Put the
; address in EAX
add dword [eax], 10 ; Add the value 10 to the DWORD value that is at
; address in EAX
pop ebp
ret
variable1 dd 1
sdigit db '%d', 0x0D, 0x0A, 0
data import
library kernel32,'KERNEL32.DLL',\
msvcrt,'MSVCRT.DLL'
import msvcrt,\
printf ,'printf'
import kernel32,\
ExitProcess,'ExitProcess'
end data
来源:https://stackoverflow.com/questions/42820117/assembly-pass-pointer-to-function