2014-09-01 176 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