理解汇编语言

drl*_*ifz 7 c assembly

我试图理解与上面的C代码有关的汇编代码.我不确定自己是否走在正确的轨道上,所以也许有人可以帮助我更好地理解这一点.

int silly(int n, int *p)
{
    int val, val2;
    if (n > 0)
        val2 = silly(n << 1, &val);
    else
        val = val2 = 0;
    *p = val + val2 + n;
    return val + val2;
}
Run Code Online (Sandbox Code Playgroud)

这会产生以下机器代码:

silly:
pushl %ebp             // Here I am making space for the function on the stack
movl %esp,%ebp         // Moving the stack pointer where the base pointer is
subl $20,%esp          // Subtracting 20 from the stack pointer to allocate more space
pushl %ebx             // Pushing the %ebx register on top of the stack
movl 8(%ebp),%ebx      // Getting the first argument(which is n) and store it in register %ebx
testl %ebx,%ebx        // The first if-statement which compares if n > 0
jle .L3                // Jump if less or equal - meaning if n < 0 then jump to .L3
addl $-8,%esp          // Add -8 to %esp to allocate more space
leal -4(%ebp),%eax     // Storing the first local variable (which is val) in %eax
pushl %eax             // Pushing the register %eax on top of the stack
leal (%ebx,%ebx),%eax  // n + n and stores it as 2n in %eax
pushl %eax             // Pushing register %eax on top of the stack (Which I find strange
                       // considering that I've just pushed %eax onto the stack above
call silly             // Call the function silly
jmp .L4                // Jump to .L4 (Unconditionally)
.p2align 4,,7          // Don't know what this means.
.L3:                   // .L3 is the else-statement
xorl %eax,%eax         // Basically making %eax = 0
movl %eax,-4(%ebp)     // Moving the value in %eax which is 0 to the first local variable 
                       // meaning val = 0
.L4:                   // .L4 is the section after the else-statement
movl -4(%ebp),%edx     // Getting val again and now storing it in %edx
addl %eax,%edx         // Adding what is in %eax (which is 0) to %edx
movl 12(%ebp),%eax     // Getting the second parameter (*p) and storing it in %eax
addl %edx,%ebx         // Adding value from %edx to %ebx - meaning val + n
movl %ebx,(%eax)       // Moving what is in %ebx and storing it in memory location of %eax
movl -24(%ebp),%ebx    // Getting the second local variable (val2) and moving it to %ebx
movl %edx,%eax         // Move val to %eax - and the return value will be in %eax
movl %ebp,%esp         
popl %ebp
ret
Run Code Online (Sandbox Code Playgroud)

我试图绕过这个,我刚开始考虑装配,所以关于这个主题的指针会非常好.关于这个汇编代码我需要问几个问题,这有助于我理解堆栈:

  • (a)变量val是否存储在堆栈中?
    (b)如果是这样,它存储的是什么字节oset(相对于%ebp)?
    (c)为什么有必要将它存放在堆栈上?

  • (a)变量val2是否存储在堆栈中?
    (b)如果是这样,它存储的是什么字节oset(相对于%ebp)?
    (c)为什么有必要将它存放在堆栈上?

  • (a)什么(如果有的话)存储在-24(%ebp)?
    (b)如果存储了某些东西,为什么需要存储它?

  • (a)什么(如果有的话)存储在-8(%ebp)?
    (b)如果存储了某些东西,为什么需要存储它?

提前致谢 :)

o11*_*11c 1

在回答你的问题之前。我没有注释代码正在做什么,而是注释所有值在寄存器或堆栈中的位置。

\n\n

参数在堆栈上,返回值在 中%eax

\n\n

寄存器%eax%ecx、 和%edx由调用者保存。所有其他寄存器,包括%ebx%ebp%esp,均由被调用者保存(%edi并且%esi未使用)。

\n\n

我对堆栈的表示法是一次 4 个字节,并且我使用;ebp 指向的位置(如果已知)。

\n\n
silly:                     ; eax: ?, ebx: ebx0, edx: ?, stack: [eip0, n, p]\n    pushl %ebp             ; eax: ?, ebx: ebx0, edx: ?, stack: [ebp0, eip0, n, p]\n    movl %esp,%ebp         ; eax: ?, ebx: ebx0, edx: ?, stack: [; ebp0, eip0, n, p]\n    subl $20,%esp          ; eax: ?, ebx: ebx0, edx: ?, stack: [?, ?, ?, ?, ?; ebp0, eip0, n, p]\n    pushl %ebx             ; eax: ?, ebx: ebx0, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]\n    movl 8(%ebp),%ebx      ; eax: ?, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]\n    testl %ebx,%ebx        ; set flags from n\n    jle .L3                ; if flags indicates <= 0, goto .L3, else fallthrough\n\n                           ; set up for calling the function\n    addl $-8,%esp          ; eax: ?, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]\n    leal -4(%ebp),%eax     ; eax: &val, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, (stackeax); ebp0, eip0, n, p]\n    pushl %eax             ; eax: &val, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]\n    leal (%ebx,%ebx),%eax  ; eax: 2*n, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]\n    pushl %eax             ; eax: 2*n, ebx: n, edx: ?, stack: [2*n, &val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p]\n    call silly             ; pushes eip; args: (2*n, &val); val will be initialized on return\n    jmp .L4                ;\n                           ;\n.p2align 4,,7              ; request alignment (there should be one before `silly:` too)\n.L3:                       ;\n    xorl %eax,%eax         ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p]\n    movl %eax,-4(%ebp)     ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n                           ;\n.L4:                       ; eax: val2=\xcf\x86(function result, 0), ebx: n, edx: ?, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    movl -4(%ebp),%edx     ; eax: val2, ebx: n, edx: val, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    addl %eax,%edx         ; eax: val2, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    movl 12(%ebp),%eax     ; eax: p, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    addl %edx,%ebx         ; eax: p, ebx: n+val+val2, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    movl %ebx,(%eax)       ; *p = n+val+val2\n    movl -24(%ebp),%ebx    ; eax: p, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    movl %edx,%eax         ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p]\n    movl %ebp,%esp         ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [; ebp0, eip0, n, p]\n    popl %ebp              ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [eip0, n, p]\n    ret                    ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [n, p]\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

停止

\n\n

返回并再次重新阅读代码。如果你不自己找出答案,那么你只会伤害自己。按照我写的评论应该很容易。

\n\n

但不管怎么说 ...

\n\n
\n\n
    \n
  1. A。val通常位于堆栈上,位于-4(%ebp)。唯一一次不是在线路上xorl %eax,%eax
    。\nb。它存储在,如、和-4(%ebp)行所示。此外,前一帧是\nc。必须位于堆栈上,以便可以获取其地址并将其传递给递归调用。leal -4(%ebp),%eaxmovl %eax,-4(%ebp)movl -4(%ebp),%edxval*p
    val
  2. \n
  3. A。val2永远不会存储在堆栈中,尽管其中一些很可能?是为其保留的空间。
    \nb. 它存储在 regixter eaxat.L4中,在 phi 函数的第一个分支上是递归调用的返回值,在第二个分支上是值0,该值也存储在 中val
    \n.\n. val2永远不需要在堆栈上,因为它的地址没有被获取,它在递归调用之前不存在,因此不需要保存,并且使用的寄存器很少,不需要溢出。
  4. \n
  5. A。是行 \nb 中 ,-24(%ebp)的保存值。%ebxpushl %ebx
    %ebx是被调用者保存的寄存器,因此必须保留其值。
  6. \n
  7. A。不,那里什么也没有。
    \nb. 如果有必要的话,很可能会发生val2泄漏。我最好的猜测是,其他三个?保留给未使用的递归调用调用者保存的寄存器:%eax%ecx%edx
  8. \n
\n