Почему простая функция встроенной сборки не будет работать правильно в GCC? - PullRequest
4 голосов
/ 17 августа 2011

У меня есть простая встроенная функция сборки, которая отлично работает в MSVC , но по какой-то причине отказывается работать под Apple GCC 4.2.1 (арка i386, принудительная 32-битнаяРежим).К счастью, гораздо более сложные функции сборки работают нормально, однако я не могу понять, почему эта работа не сработает ... К сожалению, я не могу отладить ее - судя по всему, в XCode нет окна регистров4.0.2 (это было в 3.2 версиях).

Я уверен, что проблема не связана со сборкой в ​​стиле Intel .

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

// The returned value is insane
}

Ответы [ 4 ]

8 голосов
/ 17 августа 2011

К счастью, гораздо более сложные функции сборки работают нормально [...]

Это также встроенные функции сборки? Потому что GCC использует совершенно другой синтаксис для встроенного ассемблера. Вы можете сделать синтаксис более знакомым, см. 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 указывает, что значение передается на вершину стека, что также обеспечивает правильную очистку для нас.

EDIT:

Еще одна попытка, если допустить, что 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.

2 голосов
/ 17 августа 2011

Ваш код отлично работает у меня с 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 при компиляции этого кода - параметр легко переопределить где-нибудь в проекте. Вы также можете попробовать собрать и запустить приведенный выше пример кода из командной строки, чтобы убедиться, что он работает с вашей цепочкой инструментов.

1 голос
/ 17 августа 2011

Синтаксис GCC требует, чтобы вы указали, какие переменные вы собираетесь использовать внутри кодированной части сборки. Размещенный код этого не делает и может фактически работать с произвольной памятью вместо ожидаемых переменных.

Кроме того, GCC имеет некоторую возможность использовать соглашения о вызовах, отличные от стандартного «передать все в стек» (например, fastcall и tail recursive вызовы). Размещенный код сборки предполагает, что все передается в стеке. У вас может быть несоответствие между тем, что ожидает ваш ассемблерный код и тем, что делает GCC.

Код сборки в ответе пользователя 786653 позволяет избежать этих проблем.

0 голосов
/ 22 августа 2011

У меня это работало нормально в Xcode 4.0.2 (с предупреждениями о достижении контроля в конце функции non-void). Я создал проект в 3.2.6, и когда я впервые загрузил его в Xcode 4.0.2, он не скомпилировался. Я наконец получил его для компиляции после того, как я установил 32-битную архитектуру, допустимую архитектуру на i386 и компилятор на GCC 4.2. Если для компилятора установлено значение LLVM GCC 4.2, он запускается, но функция возвращает 0.

Compiler set to LLVM GCC 4.2 Compiler set to GCC 4.2

...