У меня есть фрагмент кода 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 это не удается с ошибкой «неопределенная ссылка на `bar'». Оказывается, причина этого в том, что в Windows все идентификаторы функций с соглашением о вызовах C имеют префикс подчеркивания, но поскольку «bar» определен в сборке, он не получает этот префикс, и связывание завершается ошибкой. (Таким образом, сообщение об ошибке на самом деле жалуется на отсутствие символа _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, и должен быть искажен как таковой? Любые другие идеи?