程序集将指针传递给函数
Assembly pass pointer to function
我正在尝试将 DWORD 变量作为指针参数发送到函数中
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]
但是变量 1 是 1,而不是 11,为什么?
您确定在完成后弹出变量?
看看你的例子,我看不出变量可能是 11。它在 dd
赋值时从 1 开始,然后如果你在 lea 中的数学是正确的,那么它将是 10 . 如果你要通过调试器逐步执行此操作,你可以检查你的 lea / mov
组合是否正常工作。无论哪种方式,我都希望是 1 或 10,而不是 11。
也许您打算 add
而不是 mov
?
主要问题是当您执行 push [variable1]
时,您没有将 variable1
的 地址 压入堆栈。这会推送存储在 variable1 中的 32 位值,该值恰好是值 1。要推送地址,您可以使用 push variable1
不带括号。
在调用前将值压入堆栈时,您需要在调用后恢复堆栈。
LEA 没有获取存储在堆栈上的地址,而是获取了应该存储地址的堆栈位置的地址。我认为您正在寻找类似的东西:
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
你没有提到你所在的平台,因为你没有提供最小的完整可验证示例。上面的代码可以在 Linux 上测试:
fasm test.asm
gcc -o test -m32 test.o
当 运行 你应该得到:
11
等效的 C 代码如下所示:
#include <stdio.h>
void _InitPointer (int *ptr)
{
*ptr += 10;
return;
}
int variable1 = 1;
int main()
{
_InitPointer (&variable1);
printf ("%d\n", variable1);
return 0;
}
注意:如果在 Linux 的现代版本上,32 位程序遵循 System V i386 ABI 要求堆栈在函数调用点对齐 16 字节(或 32 字节) .我没有在上面的代码中这样做是为了简化它,但应该考虑到这一点。我不确定你是在 Linux 还是 Windows。你的问题没有说。
32 位 Windows 版本
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
我正在尝试将 DWORD 变量作为指针参数发送到函数中
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]
但是变量 1 是 1,而不是 11,为什么?
您确定在完成后弹出变量?
看看你的例子,我看不出变量可能是 11。它在 dd
赋值时从 1 开始,然后如果你在 lea 中的数学是正确的,那么它将是 10 . 如果你要通过调试器逐步执行此操作,你可以检查你的 lea / mov
组合是否正常工作。无论哪种方式,我都希望是 1 或 10,而不是 11。
也许您打算 add
而不是 mov
?
主要问题是当您执行 push [variable1]
时,您没有将 variable1
的 地址 压入堆栈。这会推送存储在 variable1 中的 32 位值,该值恰好是值 1。要推送地址,您可以使用 push variable1
不带括号。
在调用前将值压入堆栈时,您需要在调用后恢复堆栈。
LEA 没有获取存储在堆栈上的地址,而是获取了应该存储地址的堆栈位置的地址。我认为您正在寻找类似的东西:
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
你没有提到你所在的平台,因为你没有提供最小的完整可验证示例。上面的代码可以在 Linux 上测试:
fasm test.asm
gcc -o test -m32 test.o
当 运行 你应该得到:
11
等效的 C 代码如下所示:
#include <stdio.h>
void _InitPointer (int *ptr)
{
*ptr += 10;
return;
}
int variable1 = 1;
int main()
{
_InitPointer (&variable1);
printf ("%d\n", variable1);
return 0;
}
注意:如果在 Linux 的现代版本上,32 位程序遵循 System V i386 ABI 要求堆栈在函数调用点对齐 16 字节(或 32 字节) .我没有在上面的代码中这样做是为了简化它,但应该考虑到这一点。我不确定你是在 Linux 还是 Windows。你的问题没有说。
32 位 Windows 版本
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