当我尝试在 Snow Leopard 上运行使用 gcc 4.2.1 编译的代码时,出现“总线错误”
#include <stdio.h>
/*__declspec(naked)*/ void
doStuff(unsigned long int val, unsigned long int flags, unsigned char *result)
{
__asm{
push eax
push ebx
push ecx
push edx
mov eax, dword ptr[esp + 24]//val
mov ebx, dword ptr[esp + 28]//flags
//mov ecx, dword ptr[esp + 32]//result
and eax, ebx
mov result, eax
pop edx
pop ecx
pop ebx
pop eax
ret
}
}
int main(int argc, char *argv[])
{
unsigned long val = 0xAA00A1F2;
unsigned long flags = 0x00100001;
unsigned char result = 0x0;
doStuff(val, flags, &result);
printf("Result is: %2Xh\n", result);
return 0;
}
我正在使用以下命令来编译 gcc -fasm-blocks -m32 -o so so.c
没有任何错误或警告。我正在尝试在 doStuff() 函数中运行一些汇编指令并将答案分配给结果。我做错了什么?
(这台 Mac 上的 gcc
命令实际上可能是 clang,或者是 Apple 的修改,因为主线 GCC 不支持 -fasm-blocks
。)
注意:这在 Windows 上的 Visual Studio 中运行良好,但我必须注释掉 declspec(naked) 才能让 gcc 在 Mac 上编译它。
最佳答案
您收到总线错误的原因是您在汇编代码中调用ret
。 ret
使程序控制转移到堆栈顶部的返回地址,您可以通过使用 push
和 pop
来操作该地址。我强烈建议您在英特尔指令集引用中查找 ret
的作用。
下面是我在运行 Mac OS X 10.6.7 的 iMac 上编译并成功运行的代码。
#include <stdio.h>
/*__declspec(naked)*/ void
doStuff(unsigned long int val, unsigned long int flags, unsigned char *result)
{
__asm
{
push eax
push ebx
push ecx
mov eax, dword ptr[ebp + 8] //val
mov ebx, dword ptr[ebp + 12] //flags
mov ecx, dword ptr[ebp + 16] //result
and eax, ebx
mov [ecx], eax
pop ecx
pop ebx
pop eax
}
}
int main(int argc, char *argv[])
{
unsigned long val = 0xAA00A1F2;
unsigned long flags = 0x00100002;
unsigned char result = 0x0;
doStuff(val, flags, &result);
printf("Result is: %2Xh\n", result);
return 0;
}
显着的变化是:
- 删除内联程序集中的
ret
- 使用寄存器
ebp
而不是esp
来引用doStuff
的参数 - 将
flags
更改为0x00100002
更改 (1) 修复了总线错误,(2) 使参数引用更加一致,(3) 只是确保函数按预期工作的快速方法。
最后,如果您还没有熟悉 GNU 调试器 GDB,我强烈建议您熟悉一下。您可以在项目页面http://www.gnu.org/software/gdb/找到更多信息。以及有关 Mac 实现和教程的信息,请访问 https://developer.apple.com/library/archive/documentation/DeveloperTools/gdb/gdb/gdb_toc.html .
关于macos - 从 MSVC 裸函数转换总线错误 : Inline x86 assembly with GCC asm{} block on Mac OS X,,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5784824/