简体   繁体   English

为什么简单的内联汇编 function 不能在 GCC 中正常工作?

[英]Why won't simple inline assembly function work correctly in GCC?

I have a simple inline assembly function, which works fine in MSVC , but for some reason refuses to work under Apple GCC 4.2.1 (i386 arch, forced 32-bit mode).我有一个简单的内联程序集 function,它在MSVC中工作正常,但由于某种原因拒绝在Apple GCC 4.2.1 (i386 架构,强制 32 位模式)下工作。 Fortunately, much more complex assembly functions work fine, however I can't fathom why won't this one work... Unfortunately, I can't debug it - by the look of things there is no registers window in XCode 4.0.2 (it was in 3.2 versions).幸运的是,更复杂的汇编函数可以正常工作,但是我无法理解为什么这个不能工作......不幸的是,我无法调试它 - 从外观上看, XCode 4.0.2中没有寄存器 window (它在3.2版本中)。

I'm positive that the problem is not related with Intel style assembly .我很肯定这个问题与 Intel style assembly 无关

int Convert(double value)
{
     _asm
     {
         fld value
         push eax
         fistp dword ptr [esp]
         pop eax
     }

// The returned value is insane
}

Fortunately, much more complex assembly functions work fine[...]幸运的是,更复杂的汇编函数可以正常工作[...]

Are these also inline assembly functions?这些也是内联汇编功能吗? Because GCC uses a completely different syntax for inline assembler.因为 GCC 对内联汇编器使用完全不同的语法。 You can make the syntax look more familiar though, see wikipedia .不过,您可以使语法看起来更熟悉,请参阅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     }   

Is how I would do it.我会怎么做。 =m specifies that we want a memory operand to store the result in (we don't want a register as fist doesn't work with those). =m指定我们想要一个 memory 操作数来存储结果(我们不想要一个寄存器,因为fist不适用于那些)。 t specifies that the value is passed on the stack top, that also ensures proper cleanup for us. t指定该值在栈顶传递,这也确保了我们的正确清理。

EDIT:编辑:

Another thing to try, assuming gcc with xcode allows the same kind of inline assembler as msvc, is:另一件事要尝试,假设 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;
 } 

That should also shut up the warnings about missing return values you're probably getting.这也应该关闭您可能收到的有关缺少返回值的警告。 It might simply be that it is more strict about allowing you to return values from assembler blocks by writing eax than msvc.可能只是因为允许您通过编写 eax 从汇编程序块返回值比 msvc 更严格。

Your code works fine for me with Apple gcc 4.2.1:您的代码适用于 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

My guess is that you are inadvertently compiling for 64 bit.我的猜测是您无意中为 64 位编译。 Take a look at the build transcript in Xcode and make sure you can see -m32 when compiling this code - it's easy for a setting to get overriden somewhere in the project.查看 Xcode 中的构建记录,并确保在编译此代码时可以看到-m32 - 设置很容易在项目中的某处被覆盖。 You can also try building and running my code example above from the command line to make sure it works with your toolchain.您还可以尝试从命令行构建和运行我上面的代码示例,以确保它适用于您的工具链。

GCC's syntax requires you to specify which variables you're going to use inside the assembly coded portion. GCC 的语法要求您指定要在汇编编码部分中使用的变量。 The posted code doesn't do that, and may in fact be operating on random memory instead of the variables you expect to.发布的代码没有这样做,实际上可能在随机 memory 而不是您期望的变量上运行。

Additionally, GCC has some ability to use calling conventions other than the standard "pass everything on the stack" (eg., fastcall and tail recursive calls).此外,GCC 具有使用标准“传递堆栈上的所有内容”以外的调用约定的能力(例如,快速调用和尾递归调用)。 The assembly code posted assumes that everything is passed on the stack.发布的汇编代码假定所有内容都在堆栈上传递。 You may have a mismatch between what your assembly code expects and what GCC is doing.您的汇编代码所期望的与 GCC 正在执行的操作之间可能存在不匹配。

The assembly code in user786653's answer avoids these problems. user786653 的答案中的汇编代码避免了这些问题。

It worked fine for me in Xcode 4.0.2 (with warnings about control reaching end of non-void function).它在 Xcode 4.0.2 中对我来说效果很好(带有关于控制到达非空函数结束的警告)。 I created the project in 3.2.6 and when I first loaded it into Xcode 4.0.2 it wouldn't compile.我在 3.2.6 中创建了该项目,当我第一次将其加载到 Xcode 4.0.2 时,它无法编译。 I finally got it to compile after I set the Architecture to 32-bit, the Valid Architecture to i386, and the compiler to GCC 4.2.在我将架构设置为 32 位、将有效架构设置为 i386 并将编译器设置为 GCC 4.2 之后,我终于可以编译它了。 With the compiler set to LLVM GCC 4.2, it runs but the function returns 0.将编译器设置为 LLVM GCC 4.2,它会运行,但 function 返回 0。

编译器设置为 LLVM GCC 4.2编译器设置为 GCC 4.2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM