我有一个简单的内联汇编函数,在 MSVC 中工作正常,但出于某种原因拒绝在 Apple GCC 4.2.1 下工作(i386 arch,强制32位模式)。幸运的是,更复杂的汇编函数工作得很好,但是我无法理解为什么这个函数不能正常工作...不幸的是,我无法调试它 - 通过看看 XCode中没有寄存器窗口4.0.2 (它在 3.2 版本中)。
我很肯定这个问题与英特尔风格的程序集无关。。
int Convert(double value)
{
_asm
{
fld value
push eax
fistp dword ptr [esp]
pop eax
}
// The returned value is insane
}
答案 0 :(得分:8)
幸运的是,更复杂的汇编函数工作正常[...]
这些也是内联汇编功能吗?因为GCC对内联汇编程序使用completely different语法。您可以使语法看起来更熟悉,请参阅wikipedia。
1 int Convert(double value)
2 {
3 int result;
4 __asm__ __volatile__ (
5 "fist %0\n\t"
6 : "=m" (result)
7 : "t" (value)
8 );
9 return result;
10 }
我是怎么做的。 =m
指定我们想要一个内存操作数来存储结果(我们不希望寄存器fist
不能用于那些)。 t
指定值在堆栈顶部传递,这也确保了我们的正确清理。
编辑:
尝试另一件事,假设gcc与xcode允许与msvc相同的内联汇编程序,是:
int Convert(double value)
{
int result;
_asm
{
fld value
push eax
fistp dword ptr [esp]
pop eax
mov [result], eax
}
return result;
}
那也应该关闭你可能会得到的关于丢失返回值的警告。可能只是因为允许你通过编写eax而不是msvc来从汇编程序块返回值更严格。
答案 1 :(得分:2)
使用Apple gcc 4.2.1:
,您的代码可以正常使用#include <stdio.h>
static int Convert(double value)
{
_asm
{
fld value
push eax
fistp dword ptr [esp]
pop eax
}
}
int main(void)
{
int i = Convert(42.0);
printf("i = %d\n", i);
return 0;
}
$ gcc -v
Using built-in specs.
Target: i686-apple-darwin10
Configured with: /var/tmp/gcc/gcc-5666.3~123/src/configure --disable-checking --enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.2/ --with-slibdir=/usr/lib --build=i686-apple-darwin10 --program-prefix=i686-apple-darwin10- --host=x86_64-apple-darwin10 --target=i686-apple-darwin10 --with-gxx-include-dir=/include/c++/4.2.1
Thread model: posix
gcc version 4.2.1 (Apple Inc. build 5666) (dot 3)
$ gcc -Wall -m32 -O3 -fasm-blocks convert.c -o convert
convert.c: In function ‘Convert’:
convert.c:14: warning: no return statement in function returning non-void
$ ./convert
i = 42
我的猜测是你无意中为64位编译。看看Xcode中的构建脚本,并确保在编译此代码时可以看到-m32
- 设置在项目的某个地方很容易被覆盖。您还可以尝试从命令行构建和运行上面的代码示例,以确保它与您的工具链一起使用。
答案 2 :(得分:1)
GCC的语法要求您指定要在汇编编码部分中使用的变量。发布的代码不会这样做,实际上可能是在随机内存上运行而不是您期望的变量。
此外,GCC还具有使用除标准“传递堆栈中的所有内容”之外的调用约定的能力(例如,fastcall和尾递归调用)。发布的汇编代码假定所有内容都在堆栈上传递。您的汇编代码期望与GCC正在做什么之间可能不匹配。
user786653答案中的汇编代码避免了这些问题。
答案 3 :(得分:0)
在Xcode 4.0.2中它对我来说很好(有关控件到达非void函数结束的警告)。我在3.2.6中创建了项目,当我第一次将它加载到Xcode 4.0.2中时,它无法编译。在我将架构设置为32位,有效架构设置为i386,编译器设置为GCC 4.2后,我终于将其编译。将编译器设置为LLVM GCC 4.2,它会运行,但函数返回0.