Подтвердить что ты не робот

Добавление ведущих символов подчеркивания к символам сборки с помощью GCC на Win32?

У меня есть кусок кода C, который вызывает функцию, определенную в сборке. В качестве примера предположим, что foo.c содержит:

int bar(int x);  /* returns 2x */
int main(int argc, char *argv[]) { return bar(7); }

И bar.s содержит реализацию bar() в сборке x86:

.global bar
bar:    movl 4(%esp), %eax
        addl %eax, %eax
        ret

В Linux я могу легко скомпилировать и связать эти источники с GCC следующим образом:

% gcc -o test foo.c bar.s
% ./test; echo $?
14

В Windows с MinGW это происходит с ошибкой "undefined ссылка на" bar ". Оказывается, причина в том, что в Windows все идентификаторы функций с условным обозначением C имеют префикс с подчеркиванием, но поскольку в сборке определен" бар", он не получает этот префикс, а ссылка не выполняется. (Таким образом, сообщение об ошибке на самом деле жалуется на отсутствие символа _bar, а не на bar.)

Подводя итог:

% gcc -c foo.c bar.s
% nm foo.o bar.o
foo.o:
00000000 b .bss
00000000 d .data
00000000 t .text
         U ___main
         U _bar
00000000 T _main

bar.o:
00000000 b .bss
00000000 d .data
00000000 t .text
00000000 T bar

Теперь вопрос: как я могу это решить? Если бы я писал только для Windows, я мог бы просто добавить подчеркивание к идентификатору в bar.s, но тогда код разбивается на Linux. Я посмотрел варианты gcc -fleading-underscore и -fno-leading-underscore, но ни один из них ничего не делает (по крайней мере, в Windows).

Единственная альтернатива, которую я вижу сейчас, - это передать файл сборки через препроцессор C и переопределить все объявленные символы вручную, если определена WIN32, но это тоже не очень красиво.

Есть ли у кого-нибудь чистое решение? Возможно, вариант компилятора, который я контролировал? Может быть, ассемблер GNU поддерживает способ конкретного, чтобы этот конкретный символ ссылался на функцию с использованием соглашения о вызове C и должен быть искажен как таковой? Любые другие идеи?

4b9b3361

Ответ 1

Один из вариантов, хотя и опасен, заключается в том, чтобы убедить GCC опустить требуемое ABI главное подчеркивание.

  • -fleading-underscore

    Этот параметр и его аналог -fno-leading-underscore принудительно изменяют способ отображения символов C в объектном файле. Одно использование - это ссылка на устаревший ассемблерный код.

    Предупреждение: переключатель -fleading-underscore заставляет GCC генерировать код, который не является бинарным, совместимым с кодом, сгенерированным без этого коммутатора. Используйте его для соответствия двоичному интерфейсу приложения, отличного от стандартного. Не все цели обеспечивают полную поддержку этого коммутатора.

Другим, более безопасным вариантом является прямое указание GCC для использования имени.

5.39 Управление именами, используемыми в коде ассемблера

Вы можете указать имя, которое будет использоваться в коде ассемблера для функции или переменной C, написав ключевое слово asm (или __asm__) после объявления следующим образом:

     int foo asm ("myfoo") = 2;

Это указывает, что имя, которое будет использоваться для переменной foo в коде ассемблера, должно быть `` myfoo ' rather than the usual \``_foo '.

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

Не имеет смысла использовать эту функцию с нестатической локальной переменной, поскольку такие переменные не имеют имен ассемблера. Если вы пытаетесь поместить переменную в определенный регистр, см. Явные Reg Vars. GCC в настоящее время принимает такой код с предупреждением, но, вероятно, будет изменен, чтобы в будущем выпустить ошибку, а не предупреждение.

Вы не можете использовать asm таким образом в определении функции; но вы можете получить тот же эффект, написав декларацию для функции перед ее определением и разместив там asm, например:

 extern func () asm ("FUNC");

 func (x, y)
      int x, y;
 /* ... */

Вы должны убедиться, что выбранные вами имена ассемблера не противоречат каким-либо другим символам ассемблера. Кроме того, вы не должны использовать имя регистра; что приведет к совершенно недействительному ассемблерному коду. GCC пока не имеет возможности хранить статические переменные в регистрах. Возможно, это будет добавлено.

В вашем случае

extern int bar(int x) asm("bar");

должен указать GCC, что "bar использует имя asm` `bar` ', даже если это функция ccall".

Ответ 2

Вы можете использовать препроцессор C для предварительной сборки вашей сборки и использования макроса для добавления недостающих символов подчеркивания в Windows. Во-первых, вам нужно переименовать файл сборки из bar.s в bar.S(capital 'S'). Это говорит gcc использовать cpp для предварительной обработки файла.

Чтобы добавить недостающие символы подчеркивания, вы можете определить макрос "cdecl" следующим образом:

#if defined(__WIN32__)
# define cdecl(s) _##s
#else
# define cdecl(s) s
#endif

Затем используйте его следующим образом:

.global cdecl(bar)
cdecl(bar):
    movl 4(%esp), %eax
    addl %eax, %eax
    ret

Обратите внимание, что для Mac OSX также требуются ведущие символы подчеркивания, поэтому вы можете обновить первую строку макроса следующим образом:

#if defined(__WIN32__) || defined(__APPLE__)

Ответ 3

можете ли вы объявить его дважды?

.global bar
.global _bar

Я еще не написал сборку, но идентификатор .global просто действует как ярлык?

Ответ 4

Компиляторы для цели ELF не добавляют по умолчанию подчеркивания подчеркивания. Вы можете добавить -fleading-underscore при компиляции в формат ELF (под Linux). Используйте условный код в файле makefile.

Ссылка: http://opencores.org/openrisc,gnu_toolchain (выполните поиск на странице "оставить глобальные имена без изменений" )