2015-05-30 82 views
1

我在gdb中爲32位和64位intel處理器反彙編了以下代碼。32位和64位處理器的堆棧如何不同

void main() { 
5  char *args[2]; 
6 
7  args[0] = "/bin/sh"; 
8  args[1] = NULL; 
9  execve(args[0],args,NULL); 
10  exit(0); 
11 } 

以下是生成的彙編代碼。

對於64位

Dump of assembler code for function main: 
    0x000000000040105e <+0>: push %rbp 
    0x000000000040105f <+1>: mov %rsp,%rbp 
    0x0000000000401062 <+4>: sub $0x10,%rsp 
    0x0000000000401066 <+8>: movq $0x493564,-0x10(%rbp) ; <- this line 
    0x000000000040106e <+16>: movq $0x0,-0x8(%rbp) 
    0x0000000000401076 <+24>: mov -0x10(%rbp),%rax 
    0x000000000040107a <+28>: lea -0x10(%rbp),%rcx 
    0x000000000040107e <+32>: mov $0x0,%edx 
    0x0000000000401083 <+37>: mov %rcx,%rsi 
    0x0000000000401086 <+40>: mov %rax,%rdi 
    0x0000000000401089 <+43>: callq 0x433510 <execve> 
    0x000000000040108e <+48>: mov $0x0,%edi 
    0x0000000000401093 <+53>: callq 0x407560 <exit> 

對於32位

Dump of assembler code for function main: 
0x8000130 <main>:  pushl %ebp 
0x8000131 <main+1>:  movl %esp,%ebp 
0x8000133 <main+3>:  subl $0x8,%esp 
0x8000136 <main+6>:  movl $0x80027b8,0xfffffff8(%ebp) ; <- this line 
0x800013d <main+13>: movl $0x0,0xfffffffc(%ebp) 
0x8000144 <main+20>: pushl $0x0 
0x8000146 <main+22>: leal 0xfffffff8(%ebp),%eax 
0x8000149 <main+25>: pushl %eax 
0x800014a <main+26>: movl 0xfffffff8(%ebp),%eax 
0x800014d <main+29>: pushl %eax 
0x800014e <main+30>: call 0x80002bc <__execve> 
0x8000153 <main+35>: addl $0xc,%esp 
0x8000156 <main+38>: movl %ebp,%esp 
0x8000158 <main+40>: popl %ebp 
0x8000159 <main+41>: ret 
End of assembler dump. 

在上述我所標註的彙編代碼,其中i沒有理解。 64位系統聲明16位(我想要學習的位,字節或字)偏移rbp,而32位系統聲明偏離ebp的8位。 有人可以解釋堆棧指針在32位和64位系統中的差異以及它是什麼單位(位,字節或字)。

+1

* 64位系統宣佈從RBP偏移16位(位,字節或字,我想學習),而32位系統宣佈8位來自EBP *偏移 - 我相信這是個字節,而不是位。 – user35443

+1

字節。偏移量不同,因爲在64位模式下,地址佔用8個字節而不是4個。 –

回答

3
char * args[2]; 

是兩個指針的數組。在32位機器上,指針(地址,但不一定)是32位寬,而在64位機器上,指針(而不是地址)是64位寬。

也就是說,當前堆棧幀中的堆棧區域必須爲2 * pointer_width,這使得32位機器爲8,而64位機器爲16

下面在你的代碼,你可以看到

movl $0x80027b8, -0x8(%ebp) 
movl $0x0, -0x4(%ebp) 

...移動32位雙字的指針(字符串的一個地址,一個NULL)。

另一方面,64位代碼需要兩個雙字(8字節)來存儲地址。

movq $0x0, -0x8(%rbp) 
movq $0x493564, -0x10(%rbp) 
+0

「指針(而不是地址)是什麼意思是64位寬」?在'LP64'模式下,指針*和*地址總是* 64位寬,所以你的回答讓我困惑。 –

+0

@EmployedRussian對不起,我是用其他方式表示的。地址可能是64位寬,但只有在它們是虛擬的。據我所知,物理地址現在不超過52位。當然,在這種情況下,我們正在討論虛擬地址,因此聲明不適用。 – user35443

+1

'movl $ 0x0,-0xC(%ebp)'應該是'movl $ 0x0,-0x4(%ebp)',因爲0xfffffffc是十進制-4。因爲arg應該在內存中的arg ++(arg [0]在arg [1]之前)之前有意義。 –