2014-10-09 68 views
7

我想了解与上面的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; 
} 

我们得到以下的机器代码:

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 

我想换我解决这个头,我刚开始想组装等主题的指针将是非常好的。我有几个我需要问这个汇编代码,可以帮助栈我的理解的问题:

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

  • (a)变量val2是否存储在堆栈中?
    (b)如果是这样,在什么字节oset(相对于%ebp)被存储?
    (c)为什么需要将它存储在堆栈中? (a)什么(如果有的话)存储在-24(%ebp)?
    (b)如果有东西存储在那里,为什么需要存储它? (a)什么(如果有的话)存储在-8(%ebp)?(0127)
    (b)如果有东西存储在那里,为什么需要存储它?

感谢提前:)

+4

你的问题到底是什么? – o11c 2014-10-09 21:36:10

+0

我刚刚更新了这个问题。对不起:) – drleifz 2014-10-09 21:41:38

+0

注意:'val2'是未初始化的。有时。有时候'val'也是如此。 – wildplasser 2014-10-09 22:34:45

回答

1

在回答您的问题之前。我没有评论代码在做什么,我评论了所有值都在寄存器或堆栈中的位置。

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

寄存器%eax,%ecx%edx被保存。所有其他寄存器,包括%ebx,%ebp%esp,都被调用保存(%edi%esi未使用)。

我的堆栈符号一次是4个字节,我使用;作为ebp点的位置(如果已知)。

silly:      ; eax: ?, ebx: ebx0, edx: ?, stack: [eip0, n, p] 
    pushl %ebp    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebp0, eip0, n, p] 
    movl %esp,%ebp   ; eax: ?, ebx: ebx0, edx: ?, stack: [; ebp0, eip0, n, p] 
    subl $20,%esp   ; eax: ?, ebx: ebx0, edx: ?, stack: [?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    pushl %ebx    ; eax: ?, ebx: ebx0, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl 8(%ebp),%ebx  ; eax: ?, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    testl %ebx,%ebx  ; set flags from n 
    jle .L3    ; if flags indicates <= 0, goto .L3, else fallthrough 

          ; set up for calling the function 
    addl $-8,%esp   ; eax: ?, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    leal -4(%ebp),%eax  ; eax: &val, ebx: n, edx: ?, stack: [?, ?, ebx0, ?, ?, ?, ?, (stackeax); ebp0, eip0, n, p] 
    pushl %eax    ; eax: &val, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    leal (%ebx,%ebx),%eax ; eax: 2*n, ebx: n, edx: ?, stack: [&val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    pushl %eax    ; eax: 2*n, ebx: n, edx: ?, stack: [2*n, &val, ?, ?, ebx0, ?, ?, ?, ?, val=?; ebp0, eip0, n, p] 
    call silly    ; pushes eip; args: (2*n, &val); val will be initialized on return 
    jmp .L4    ; 
          ; 
.p2align 4,,7    ; request alignment (there should be one before `silly:` too) 
.L3:      ; 
    xorl %eax,%eax   ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, ?; ebp0, eip0, n, p] 
    movl %eax,-4(%ebp)  ; eax: val=0, ebx: n, edx: ?, stack: [ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
          ; 
.L4:      ; eax: val2=φ(function result, 0), ebx: n, edx: ?, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl -4(%ebp),%edx  ; eax: val2, ebx: n, edx: val, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %eax,%edx   ; eax: val2, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl 12(%ebp),%eax  ; eax: p, ebx: n, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    addl %edx,%ebx   ; eax: p, ebx: n+val+val2, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebx,(%eax)  ; *p = n+val+val2 
    movl -24(%ebp),%ebx ; eax: p, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %edx,%eax   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [..., ebx0, ?, ?, ?, ?, val; ebp0, eip0, n, p] 
    movl %ebp,%esp   ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [; ebp0, eip0, n, p] 
    popl %ebp    ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [eip0, n, p] 
    ret     ; eax: val+val2, ebx: ebx0, edx: val+val2, stack: [n, p] 

STOP

返回并重新读取代码。如果你不自己想出答案,你只会伤害自己。我写的评论应该很容易。

但无论如何...


  1. 一个。 val通常位于堆栈上,位于-4(%ebp)。唯一不是的是xorl %eax,%eax
    b。它存储在-4(%ebp),如线路leal -4(%ebp),%eaxmovl %eax,-4(%ebp)movl -4(%ebp),%edx所示。此外,前一帧的val*p
    c。 val必须位于堆栈上,以便其地址可以被接受并传递给递归调用。
  2. a。 val2永远不会存储在堆栈中,尽管很可能其中一些?是为其保留的空间。 b。它存储在regixter eax.L4,它在phi函数的第一个分支上是递归调用的返回值,在第二个分支上是值0,它也存储在val中。
    c。 val2永远不需要在堆栈上,因为它的地址没有被占用,它在递归调用之前不存在,所以它不需要被保存,并且没有足够的寄存器在使用,因此不需要溢出。
  3. a。 -24(%ebp)是保存的值%ebx,从行pushl %ebx
    b。 %ebx是一个被调用者保存的寄存器,所以它的值必须保留。
  4. a。不,没有什么。 b。如果有必要泄漏,最有可能是val2。我最好的猜测是其他三个?被保留用于递归调用呼叫者保存的未使用寄存器:%eax,%ecx%edx
0

你已经问了很多。

我会用这部分开始...

.p2align 4,,7 // Don't know what this means.

明白了;模糊,不是吗!

程序员(在你的情况下看起来像编译器)想要L3:的指令位于所谓的“16字节边界”。

你可以阅读关于那东西HERE的细节。如果这没有意义,请回到这里,我会解释一些。