2009-09-08 53 views
5

比方說,我們有以下的C++代碼:定義變量中的C++內聯彙編

int var1; 

__asm { 
    mov var1, 2; 
} 

現在,想我所知道的是,如果我不想定義__asm指令外VAR1,我需要做些什麼才能把它放進去。它甚至有可能嗎?

由於

回答

12

要做到這一點,您需要使用_declspec(裸體)創建一個「裸」方法,並編寫通常由編譯器創建的序言和結語。

一個序言的目的是:

  • 設置EBP和ESP
  • 保留空間上堆疊爲局部變量
  • 保存寄存器應在函數的主體被修改

的結語有:

  • 恢復保存的寄存器值
  • 清理局部變量

這裏預留空間是一個標準的序言

push  ebp    ; Save ebp 
mov   ebp, esp   ; Set stack frame pointer 
sub   esp, localbytes ; Allocate space for locals 
push  <registers>  ; Save registers 

和一個標準的結尾處理:

pop   <registers> ; Restore registers 
mov   esp, ebp  ; Restore stack pointer 
pop   ebp   ; Restore ebp 
ret      ; Return from function 

你的局部變量將從(ebp - 4)開始,然後下降到(ebp - 4 - localbytes)。功能參數將從(ebp + 8)開始並向上。

3

它不可能創建彙編一個C變量:C編譯器必須知道有關變量(即,其類型和地址),這意味着它具有在C代碼中聲明。

可以做的是通過C中的extern聲明訪問彙編程序中定義的符號。這對於具有自動存儲持續時間的變量來說不起作用,儘管這些變量沒有固定的地址,而是相對於基址指針。

如果您不想訪問asm塊之外的變量,則可以使用堆棧來存儲彙編程序本地數據。請記住,你必須堆棧​​指針恢復到以前的值在離開asm塊時,如

sub esp, 12  ; space for 3 asm-local 32bit vars 
mov [esp-8], 42 ; set value of local var 
[...] 
push 0xdeadbeaf ; use stack 
[...]    ; !!! 42 resides now in [esp-12] !!! 
add esp, 16  ; restore esp 

如果你不想局部變量的相對地址改變,只要你操作堆棧(即使用pushpop),則必須按照cedrou's answer中所述建立堆棧幀(即,將堆棧的基址保存在ebp中,並將地址相對於此值保存)。

+0

確定子ESP,3會給空間3 32位瓦爾?我的想法是,對於每個32位變量,我必須從esp中取4個變量。 – 2009-09-08 21:47:51

+0

至少C++在內部定義如下:var_4 = dword ptr -4 – 2009-09-08 21:48:27

+0

你是對的 - 不應該在深夜回答問題;) – Christoph 2009-09-08 22:53:44

3

局部變量分配和釋放由通過ESP寄存器操作的調用堆棧上的可用空間,即:

__asm 
{ 
    add esp, 4 
    mov [esp], 2; 
    ... 
    sub esp, 4 
} 

一般來說,這是通過建立一個「堆棧幀」爲調用函數更好地處理反而,然後訪問使用偏移局部變量(和功能參數)的框架內,而是採用了ESP直接註冊,即:

__asm 
{ 
    push ebp 
    mov ebp, esp 
    add esp, 4 
    ... 
    mov [ebp-4], 2; 
    ... 
    mov esp, ebp 
    pop ebp 
}