64位元變數在32位元跟64位元的不同 -- 從assemble的角度來看



OS: Ubuntu x86_64
gcc: gcc version 4.7.3 

最近看了一本關於Debug的書,把好久沒看的Assembly也看了一下。對於以前寫C語言其實都不太會去看gcc會把你的code轉成什麼樣的assembly都不太關心。那也剛好最近比較有空(空了好久了 XD)就看到書上有寫有關64位元的變數在這兩個架構上的assembly會有不同,但書上也只是寫個簡單的敘述。

我也想說直接Dump Assembly直接看會更清楚。所以我做了以下的簡單的實驗。

1. Source Code

這是我要看的source code主要只是看64位元的變數在32位元跟64位元架構的assembly有什麼不同。所以只有只有簡單的兩行。所以我assemble只有專注於gcc會怎樣處理這個 變數。

首先我定義了一個unsigned long long 64位元的變數,並且給他一個64位元的值。

#include <stdio.h>

int main(int argc, const char *argv[])
{
    unsigned long long val64 = 0;
    val64 = 0xffffeeeeddddcccc;
         
    return 0;
}


2. 32位元Assembly 

因為我的電腦是x86_64的OS,所以要編譯32位元的assembly要在gcc的參數輸入-m32來讓gcc知道我們要編譯成32位元


$> gcc -Wall -m32 -O0 main.c -o assemble32
$> objdump -d --no-show-raw-insn assemble32

080483ec <main>:                                                                   
   80483ec:   push   %ebp                                                            
   80483ed:   mov    %esp,%ebp                                                       
   80483ef:   and    $0xfffffff8,%esp                                                
   80483f2:   sub    $0x10,%esp                                                      
   80483f5:   movl   $0x0,0x8(%esp)                                                  
   80483fd:   movl   $0x0,0xc(%esp)                                                  
   8048405:   movl   $0xddddcccc,0x8(%esp)                                           
   804840d:   movl   $0xffffeeee,0xc(%esp)                                           
   8048415:   mov    $0x0,%eax                                                       
   804841a:   leave                                                                  
   804841b:   ret                                                                    
   804841c:   xchg   %ax,%ax                                                         
   804841e:   xchg   %ax,%ax 

3. 64位元Assembly 

$> gcc -Wall -O0 main.c -o assemble
$> objdump -d --no-show-raw-insn assemble

00000000004004ec <main>:                                                            
  4004ec:   push   %rbp                                                             
  4004ed:   mov    %rsp,%rbp                                                        
  4004f0:   mov    %edi,-0x14(%rbp)                                                 
  4004f3:   mov    %rsi,-0x20(%rbp)                                                 
  4004f7:   movq   $0x0,-0x8(%rbp)                                                  
  4004ff:   movabs $0xffffeeeeddddcccc,%rax                                         
  400509:   mov    %rax,-0x8(%rbp)                                                  
  40050d:   mov    $0x0,%eax                                                        
  400512:   pop    %rbp                                                             
  400513:   retq                                                                    
  400514:   nopw   %cs:0x0(%rax,%rax,1)                                             
  40051e:   xchg   %ax,%ax

4. 討論 

看得出來32跟64的差別了嗎?主要是在分配值的時候32位元要將資料拆成兩份分別存入在兩個32位元的位置上來模擬64位元的變數。

所以32位元上會花兩步movl來處理64位元的變數,所以設計上就要很注意這個問題了。



張貼留言

這個網誌中的熱門文章

解釋scope.$apply用來做什麼? -- AngularJS

Unions 在C語言的簡單介紹

JavaScript的Timer用法