Assembly 指向函数的程序集传递指针

Assembly 指向函数的程序集传递指针,assembly,x86,libc,calling-convention,fasm,Assembly,X86,Libc,Calling Convention,Fasm,我试图将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

我试图将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]

但是variable1是1,而不是11,为什么?

您要确保完成后弹出vars

看看你的例子,我发现变量不可能是11。在
dd
作业中,它从1开始,如果你在lea中的数学是正确的,那么它将是10。如果要通过调试器逐步执行此操作,可以检查
lea/mov
组合是否正常工作。无论哪种情况,我都会期望1或10,而不是11


也许你想添加
而不是
mov

您是否确保完成后弹出VAR

看看你的例子,我发现变量不可能是11。在
dd
作业中,它从1开始,如果你在lea中的数学是正确的,那么它将是10。如果要通过调试器逐步执行此操作,可以检查
lea/mov
组合是否正常工作。无论哪种情况,我都会期望1或10,而不是11


也许你想添加
而不是
mov

主要问题是,当您执行
推送[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
跑步时,您应获得:

十一,

等效的C代码如下所示:

#include <stdio.h>

void _InitPointer (int *ptr)
{
    *ptr += 10;
    return;
}

int variable1 = 1;

int main()
{
    _InitPointer (&variable1);
    printf ("%d\n", variable1);
    return 0;
}

主要问题是,在执行
推送[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
跑步时,您应获得:

十一,

等效的C代码如下所示:

#include <stdio.h>

void _InitPointer (int *ptr)
{
    *ptr += 10;
    return;
}

int variable1 = 1;

int main()
{
    _InitPointer (&variable1);
    printf ("%d\n", variable1);
    return 0;
}

确保完成后你能打开你的Var是吗?看看你的例子,我发现变量不可能是11。在
dd
作业中,它从1开始,如果
lea
中的数学正确,那么它将是10。如果要通过调试器逐步执行此操作,可以检查
lea/mov
组合是否正常工作。无论哪种情况,我都会期望1或10,而不是11。也许你是想
add
而不是`
mov
?在调用后,我添加了pop[variable1],它可以工作。很抱歉,我是想添加而不是mov。只是为了完整性:你假设了被调用方堆栈清理约定,但实现了调用方堆栈清理约定。通过清理堆栈,您可以自己有效地解决此问题。看看你为什么自己解决了问题。为什么我可以“推他之后不弹出数组”?按my_数组调用my_func;按我的数组调用我的函数,确保完成后弹出变量是吗?看看你的例子,我发现变量不可能是11。在
dd
作业中,它从1开始,如果
lea
中的数学正确,那么它将是10。如果要通过调试器逐步执行此操作,可以检查
lea/mov
组合是否正常工作。无论哪种情况,我都会期望1或10,而不是11。也许你是想
add
而不是`
mov
?在调用后,我添加了pop[variable1],它可以工作。很抱歉,我是想添加而不是mov。只是为了完整性:你假设了被调用方堆栈清理约定,但实现了调用方堆栈清理约定。通过清理堆栈,您可以自己有效地解决此问题。看看你为什么自己解决了问题。为什么我可以“推他之后不弹出数组”?按my_数组调用my_func;push my_array call my_funcI在Windows上。您说过“LEA没有获取存储在堆栈上的地址,而是获取应该存储地址的堆栈位置的地址。”因此,如果
push[variable]
没有发送变量的地址,那么它是如何正常工作的?我猜
leaeax,dword[ebp+8]
正在加载堆栈地址,变量的值在哪里,然后
mov dword[eax],10'正在将10加载到堆栈地址,该值在哪里,但原始的
变量'是如何变化的?因为当我们按值发送参数时,复制(从C)@Alatriste
push[variable1]
的编译器按值推送
variable1
。将值1放在堆栈顶部(不是variable1的地址)
leaeax,dword[ebp+8]
将值1存储在堆栈上的地址(不是
variable1
的实际位置)移动到eax中。然后使用
add
修改堆栈上的值。返回
pop[variable1]
后,从堆栈顶部取出修改后的值,并将其存储(复制)到
variable1
的内存地址。虽然这是可行的,但事实并非如此