Ryan
Ryan

Reputation: 1501

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). 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).

I'm positive that the problem is not related with Intel style assembly.

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

// The returned value is insane
}

Upvotes: 4

Views: 4185

Answers (4)

SSteve
SSteve

Reputation: 10698

It worked fine for me in Xcode 4.0.2 (with warnings about control reaching end of non-void function). I created the project in 3.2.6 and when I first loaded it into Xcode 4.0.2 it wouldn't compile. 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. With the compiler set to LLVM GCC 4.2, it runs but the function returns 0.

Compiler set to LLVM GCC 4.2 Compiler set to GCC 4.2

Upvotes: 0

Max Lybbert
Max Lybbert

Reputation: 20021

GCC's syntax requires you to specify which variables you're going to use inside the assembly coded portion. The posted code doesn't do that, and may in fact be operating on random memory instead of the variables you expect to.

Additionally, GCC has some ability to use calling conventions other than the standard "pass everything on the stack" (eg., fastcall and tail recursive calls). 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.

The assembly code in user786653's answer avoids these problems.

Upvotes: 1

user786653
user786653

Reputation: 30450

Fortunately, much more complex assembly functions work fine[...]

Are these also inline assembly functions? Because GCC uses a completely different syntax for inline assembler. You can make the syntax look more familiar though, see 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). t specifies that the value is passed on the stack top, that also ensures proper cleanup for us.

EDIT:

Another thing to try, assuming gcc with xcode allows the same kind of inline assembler as msvc, is:

 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.

Upvotes: 8

Paul R
Paul R

Reputation: 212929

Your code works fine for me with 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. 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. You can also try building and running my code example above from the command line to make sure it works with your toolchain.

Upvotes: 2

Related Questions