2014-09-01 178 views
1

我在C++中有inline asm問題。我試圖實現快速strlen,但它不工作 - 當我使用__declspec(naked)關鍵字調試器顯示輸入地址爲0x000000,當我不使用該關鍵字時,eax指向一些垃圾,函數返回各種值。C++將參數傳遞給內聯彙編程序函數

這裏是代碼:

int fastStrlen(char *input) // I know that function does not calculate strlen 
{        // properly, but I just want to know why it crashes 
    _asm      // access violation when I try to write to variable x 
    { 
     mov ecx, dword ptr input 
      xor eax, eax 
     start: 
      mov bx, [ecx] 
      cmp bl, '\0' 
      je Sxend 
      inc eax 
      cmp bh, '\0' 
      je Sxend 
      inc eax 
      add ecx, 2 
      jmp start 
     Sxend: 
      ret 
    } 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    char* test = "test"; 
    int x = fastStrlen(test); 
    cout << x; 
    return 0; 
} 

任何人可以點我什麼我做錯了?

+0

你想'mov'不是'lea'。此外,你沒有返回長度,你正在返回一個地址。將16位寄存器與'\ 0''比較是不會做你想要的。順便說一句,這不會非常快,而且你不需要真正做到這一點。 – Jester 2014-09-01 17:48:34

+0

@Jester mov既不工作也不錯,我知道我現在正在返回錯誤的val,但我改變了這個,因爲我認爲這些錯誤是因爲使用ESI寄存器; _; – encoree1337 2014-09-01 17:50:08

+0

它是ABI的具體(實際上取決於處理器,操作系統和編譯器)。 – 2014-09-01 17:52:12

回答

1

請勿使用__declspec(naked),因爲在這種情況下,編譯器不會生成epilogue和prologue指令,您需要生成序言,就像編譯器期望的那樣,如果要訪問參數fastStrlen。既然你不知道編譯器期望什麼,你應該讓它生成序言。

這意味着您不能僅僅使用ret返回給調用者,因爲這意味着您提供了自己的後記。既然你不知道編譯器使用了什麼序言,你不知道你需要實現什麼結尾來反轉它。相反,將返回值分配給在內聯彙編語句之前在函數內聲明的C變量,並在普通的C語句中返回該變量。例如:

int fastStrlen(char *input) 
{ 
    int retval; 
    _asm 
    { 
     mov ecx, dword ptr input 
     ... 
    Sxend: 
     mov retval,eax 
    } 
    return retval; 
} 

在你的評論中所指出你的代碼將無法改善您的編譯器的運行時庫strlen實施。它還會讀取偶數長度字符串的末尾,如果字符串末尾的字節未映射到內存中,則會導致內存故障。

+0

除非編譯器死腦筋,否則它應該能夠在沒有任何序言的情況下引用相對於'esp'的參數。 – Jester 2014-09-01 18:38:39

+0

@Jester它可能會,但它會不得不假定內聯程序集沒有建立自己的序幕。 – 2014-09-01 18:48:10

+0

這是一個很好的觀點。 – Jester 2014-09-01 18:49:06