在汇编中如何通过 ref 传递参数

CSh*_*p-n 1 c# x86 assembly calling-convention

我对组装非常陌生,所以请耐心等待。
我有这段代码,它通过引用函数传递值以对其进行修改:

[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Main()
{
    int a = 5 ;
    Modify(ref a); 
    Console.WriteLine(a); 
    
                      
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Modify (ref int a )
{
 
    a = 77 ; 
}
Run Code Online (Sandbox Code Playgroud)

该代码生成的程序集是

[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Main()
{
    int a = 5 ;
    Modify(ref a); 
    Console.WriteLine(a); 
    
                      
}
[MethodImpl(MethodImplOptions.NoOptimization | MethodImplOptions.NoInlining)]
static void Modify (ref int a )
{
 
    a = 77 ; 
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:在指令 L0006 : mov [ebp-4], eax 中,这会将寄存器 eax 的值复制到 Ebp-4 指向的内存位置,但 Ebp-4 没有指向任何内容?我缺少什么?

xiv*_*r77 5

发布未优化的程序集会让事情变得更加混乱,但基本上,这些行,

push ebp
mov ebp, esp
Run Code Online (Sandbox Code Playgroud)

指向ebp该函数堆栈帧顶部附近。(即将EBP设置为帧指针)。

在函数入口处[esp]有返回地址。Anypush将首先减esp4(假设是 32 位环境)并将值存储在新的[esp]. 使用push ebp, [esp](减 4)存储 的旧值ebpmov ebp, esp并使ebp = esp.

   push eax
Run Code Online (Sandbox Code Playgroud)

该指令只是一种sub esp, 4为一个双字 ( int) 大小的局部变量保留堆栈空间的紧凑方法。在此之前,ESP = EBP,因此新空间位于地址处ebp-4,无论运行时发生什么。

xor eax, eax                    ; eax = 0
mov [ebp-4], eax                ; store EAX, possibly to zero-init   int a ?
mov dword ptr [ebp-4], 5
Run Code Online (Sandbox Code Playgroud)

您可以忽略前两行。它之所以存在,是因为您决定关闭优化,这通常会使事情变得更加混乱。最后一行mov dword ptr [ebp-4], 5覆盖 写入的值mov [ebp-4], eax

您无法写入,mov dword ptr [ebp], 5因为正如我之前提到的[ebp],正在存储旧值ebp

根据 fastcall 调用约定,函数调用在 ECX 中获取其 arg。该寄存器加载有一个使用LEA 指令的指针:[ebp-4]

lea ecx, [ebp-4]          ; ECX = ebp-4.   (Not [ebp-4], it's not a load)
Run Code Online (Sandbox Code Playgroud)

用 C 术语来说,它&a与局部变量的地址完全相同。LEA 计算地址,然后将其放入目标寄存器中,而不是使用它从内存加载。

请注意,在第一个函数调用返回,内存将被重新加载:

mov ecx, [ebp-4]         ; load a  as the arg for the next function call
call System.Console.WriteLine(Int32)
Run Code Online (Sandbox Code Playgroud)