1. 程式人生 > >64位和32位的暫存器和彙編的比較

64位和32位的暫存器和彙編的比較

64位暫存器分配的不同

暫存器比較
區別有:

  • 64位有16個暫存器,32位只有8個。但是32位前8個都有不同的命名,分別是e _ ,而64位前8個使用了r代替e,也就是r _。e開頭的暫存器命名依然可以直接運用於相應暫存器的低32位。而剩下的暫存器名則是從r8 - r15,其低位分別用d,w,b指定長度。
  • 32位使用棧幀來作為傳遞的引數的儲存位置,而64位使用暫存器,分別用rdi,rsi,rdx,rcx,r8,r9作為第1-6個引數。rax作為返回值
  • 64位沒有棧幀的指標,32位用ebp作為棧幀指標,64位取消了這個設定,rbp作為通用暫存器使用
  • 64位支援一些形式的以PC相關的定址,而32位只有在jmp的時候才會用到這種定址方式。

    64位(新增)彙編指令的不同

    mov指令
    mov指令和push pop擴充套件了movq系列的mov和pushq以及popq用來操作quad word。

    注意:movabsq不是32位的擴充套件,是純新增的指令。用來將一個64位的字面值直接存到一個64位暫存器中。因為movq只能將32位的值存入,所以新增了這樣一條指令。

算術指令
比較和test指令

順帶提一個小問題,64位的彙編程式碼在ret之前可能會加一句rep,這裡的rep沒有實際意義,只是出於amd處理器的原因,避免jmp所到達的地方直接就是ret,這樣會使得處理器執行更快一些。

過程(函式)呼叫的不同

  • 引數通過暫存器傳遞(見前文)
  • callq 在棧裡存放一個8位的返回地址
  • 許多函式不再有棧幀,只有無法將所有本地變數放在暫存器裡的才會在棧上分配空間。
  • 函式可以獲取到棧至多128位元組的空間。這樣函式就可以在不更改棧指標的情況下在棧上儲存資訊(也就是說,可以提前用rsp以下的128位元組空間,這段空間被稱為red zone,在x86-64裡,時刻可用)
  • 不再有棧幀指標。現在棧的位置和棧指標相關。大多數函式在呼叫的一開始就分配全部所需棧空間,之後保持棧指標不改變。
  • 一些暫存器被設計成為被呼叫者-儲存的暫存器。這些必須在需要改變他們值的時候儲存他們並且之後恢復他們。

    引數傳遞的不同

  • 6個暫存器用來傳遞引數(見前文)
  • 剩下的暫存器按照之前的方式傳遞(不過是與rsp相關了,ebp不再作為棧幀指標,並且從rsp開始第7個引數,rsp+8開始第8個,以此類推)
  • 呼叫時,rsp向下移動8位(存入返回地址),暫存器引數無影響,第7個及之後的引數現在則是從rsp+8開始第7個,rsp+16開始第8個,以此類推

棧幀的不同

很多情況下不再需要棧幀,比如在沒有呼叫別的函式,且暫存器足以儲存引數,那麼就只需要儲存返回地址即可。
需要棧幀的情況:

  • 本地變數太多,暫存器不夠
  • 一些本地變數是陣列或結構體
  • 函式使用了取地址操作符來計算一個本地變數的地址
  • 函式必須用棧傳送一些引數給另外一個函式
  • 函式需要儲存一些由被呼叫者儲存的暫存器的狀態(以便於恢復)

但是現在的棧幀經常是固定大小的,在函式呼叫的最開始就被設定,在整個呼叫期間,棧頂指標保持不變,這樣就可以通過對其再加上偏移量來對相應的值進行操作,於是EBP就不再需要作為棧幀指標了。

雖然很多時候我們認為沒有“棧幀”,但是每次函式呼叫都一定有一個返回地址被壓棧,我們可以也認為這一個地址就是一個“棧幀”,因為它也儲存了呼叫者的狀態。