2017-04-16 151 views
0

我有这个C代码是反汇编(AT & T),我有两个东西混淆。首先,我的理解是EBP-4应该是堆栈中的第一个局部变量(这里是int i)。我明确在EBP-8这里。为什么是这样?汇编局部变量和寄存器

其次,在对它们进行算术运算之前,是否需要将值移入寄存器? (这是一个x86 32位机)例如:

0x08048402 <+21>: mov 0x8(%ebp),%eax //move parameter a into eax 0x08048405 <+24>: add %eax,-0x4(%ebp) //r += a

为什么不能此是:

0x08048405 <+24>: add 0x8(%ebp),-0x4(%ebp) //r += a

的C代码:

int loop_w (int a, int b){  
    int i = 0;  
    int r = a;  
    while (i < 256){   
     r += a;   
     a -= b;   
     i += b; 
    } 
return r; 

拆卸:

Dump of assembler code for function loop_w: 
    0x080483ed <+0>:  push %ebp 
    0x080483ee <+1>:  mov %esp,%ebp 
    0x080483f0 <+3>:  sub $0x10,%esp 
---------------Above is for stack setup----------------- 
    0x080483f3 <+6>:  movl $0x0,-0x8(%ebp)   //I=0 
    0x080483fa <+13>: mov 0x8(%ebp),%eax   //move parameter a into eax 
    0x080483fd <+16>: mov %eax,-0x4(%ebp)  //move a into local var (r=a) 
    0x08048400 <+19>: jmp 0x8048414 <loop_w+39> //start while loop 
    0x08048402 <+21>: mov 0x8(%ebp),%eax  //move parameter a into eax 
    0x08048405 <+24>: add %eax,-0x4(%ebp)  //r += a 
    0x08048408 <+27>: mov 0xc(%ebp),%eax  //move parameter b into eax 
    0x0804840b <+30>: sub %eax,0x8(%ebp)  //a += parameter b 
    0x0804840e <+33>: mov 0xc(%ebp),%eax  //move parameter b into eax 
    0x08048411 <+36>: add %eax,-0x8(%ebp)  //i+=b 
    0x08048414 <+39>: cmpl $0xff,-0x8(%ebp)   //compare i to 256 
    0x0804841b <+46>: jle 0x8048402 <loop_w+21> //continue loop if failed condition 
=> 0x0804841d <+48>: mov -0x4(%ebp),%eax  //move r into eax 
    0x08048420 <+51>: leave 
    0x08048421 <+52>: ret    //return eax 
End of assembler dump. 
+0

这一切都取决于编译器是否在入口处或从堆栈分配后(后者更常见)分配堆栈起始处的变量。请注意,按照递增的内存顺序,我位于r之前(正常情况下)。 – user3344003

回答

2

编译器可以决定要放置局部变量的任何位置。由于对齐的原因,它可能会将它放在%ebp-8。

第二个问题 - 变量是否必须在操作前加载到寄存器中,取决于操作和架构提供的指令集。

您提到过x86。对于这种体系结构尤其如此,X86不允许带有两个内存操作数的指令(是的,有一些例外)。

您可以搜索每个指令的基础知道他们允许什么样的操作数。

+0

好的答案,简洁明了。 –

+0

谢谢。我正在研究这个 - 所以如果我将汇编代码写入C代码(在纸上),那么说%ebp-4是“我”然后呢? – KenP

+0

是的,假设%ebp-4是i是错误的。您可能会想要查看生成的程序集并确定堆栈中每个变量的偏移量,但这不是可伸缩的,也不是可移植的。相反,你可以看看gcc和clang支持的扩展内联汇编。它们允许您编写变量名称而不是偏移量,编译器会为您放置适当的地址(或注册表)。 –