Ошибка шины: встроенная сборка x86 с GCC на Mac OS X - PullRequest
4 голосов
/ 26 апреля 2011

При попытке запустить этот код, скомпилированный с помощью gcc 4.2.1 на Snow Leopard, я получаю сообщение "Ошибка шины"

#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 () и назначить ответ на результат.Что я делаю не так?

Примечание. Это отлично работало в Visual Studio на Windows, но мне пришлось закомментировать declspec (голый), чтобы gcc скомпилировал его на Mac.

Ответы [ 2 ]

6 голосов
/ 26 апреля 2011

Причина, по которой вы получаете ошибку шины, заключается в том, что вы вызываете ret в своем коде сборки. ret заставляет программный элемент управления перейти на адрес возврата в верхней части стека, которым вы манипулируете, используя push и pop. Я настоятельно рекомендую посмотреть, что делает ret в Справочнике по набору инструкций Intel.

Ниже приведен код, который я скомпилировал и успешно выполнил на iMac под управлением Mac OS X 10.6.7.

#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;
}

Заметные изменения:

  1. Снятие ret во встроенной сборке
  2. Использование регистра ebp вместо esp для ссылки на параметры doStuff
  3. Изменение flags на 0x00100002

Изменение (1) исправляет ошибку шины, (2) делает ссылку на параметры несколько более согласованной, а (3) это просто быстрый способ убедиться, что функция работает должным образом.

Наконец, я настоятельно рекомендую вам ознакомиться с отладчиком GNU, GDB, если вы этого еще не сделали. Вы можете найти больше информации об этом на странице проекта http://www.gnu.org/software/gdb/, а также информацию о реализации Mac и учебном руководстве по http://developer.apple.com/library/mac/#documentation/DeveloperTools/gdb/gdb/gdb_toc.html.

РЕДАКТИРОВАТЬ: Добавлена ​​основная информация / ссылка на GDB,

1 голос
/ 26 апреля 2011

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

Типичный пролог дляфункция без локальных переменных при использовании указателя кадра может выглядеть следующим образом:

push ebp
mov ebp, esp

Это сохраняет указатель кадра вызывающей стороны в стеке и делает текущий указатель кадра равным указателю стека во время входа в функцию.

Соответствующим эпилогом будет:

pop ebp
ret

, который восстанавливает предыдущий указатель кадра и возвращает его вызывающей стороне.

Если вы скажете gcc не использовать указатели кадра (-fomit-frame-pointer), соответствующий пролог будет пустым, а в эпилоге будет просто ret.

Что __declspec(naked), вероятно, похоже на __attribute__((naked)) ( атрибутов функции gcc ) gcc), который работает только для некоторых архитектур, а не для x86.Итак, на gcc лучше оставить возвращение вызывающей стороне компилятору, как вам советовал Дин Пучек.

...