«Ошибка: обратная ссылка на неизвестную метку ...» во встроенной сборке MinGW - PullRequest
2 голосов
/ 27 февраля 2010

Еще раз, я играю со встроенной сборкой MinGW.

#include <stdio.h>

int foobar(int);

int main(){
 int n = 0;
 printf("Number: ");
 scanf("%d", &n);
 printf("\n%d",foobar(n));
 return 0;
}

int foobar(int num){
 int result = 0;
 asm(".intel_syntax noprefix\n");
 asm("mov eax, num\n");
 asm("add eax, 110b\n");
 asm("sub eax, 2\n");
    asm("mov result, eax\n");
 return result;
}

Скомпилируйте это:

C: \ Users \ Andre \ Codes> gcc asmtest.c -o asmtest -masm = intel

Ой, есть ошибки:

C: \ Users \ Andre \ AppData \ Local \ Temp \ ccqny4yb.s: Сообщения ассемблера: C: \ Users \ Andre \ AppData \ Local \ Temp \ ccqny4yb.s: 53: Ошибка: обратная ссылка на неизвестную метку "110:"

Что здесь не так? Я думаю, что мой код уже действителен?

1 Ответ

1 голос
/ 27 февраля 2010

GCC лучше всего работает со сборкой в ​​стиле AT & T, а GAS не поддерживает весь синтаксис Intel. Ваша непосредственная проблема возникает из-за того, что 110b не интерпретируется как число, но это еще не все.

Вы не можете ссылаться на переменные напрямую в синтаксисе встроенного ассемблера GCC. Вам нужно будет написать это так (используя значение по умолчанию -masm=att):

int foobar(int num) {
    int result;
    asm("mov %1, %%eax\n\t"
        "add $6, %%eax\n\t"
        "sub $2, %%eax\n\t"
        "mov %%eax, %0"
        : "=g" (result)
        : "g" (num)
        : "eax", "cc");
    return result;
}

После первого двоеточия - список разделенных запятыми выходных операндов. Поскольку "=g" (result) является первым ограничением, result получает псевдоним %0. "=g" указывает GCC, что %0 может быть любым регистром или памятью общего назначения и только для записи. (+ вместо = будет означать чтение-запись. GCC может решить повторно использовать один и тот же регистр для нескольких целей, поэтому вы должны четко указать, как именно все будет использоваться.)

После второго двоеточия указывается разделенный запятыми список входных операндов. Поскольку "g" (num) является вторым ограничением, num получает псевдоним %1. "g" означает, что он будет прочитан только из.

После третьего двоеточия - список сгустков, разделенных запятыми. Это говорит GCC, что встроенная сборка может изменить эти регистры / память, даже если они не являются ни входными, ни выходными, поэтому GCC должна перезагрузить любую информацию, которую она хранит в них, через встроенную сборку. Здесь мы явно меняем %eax, и регистр кода (флагов) условий также зависит от add/sub.

Посмотрите на сборку, сгенерированную компилятором:

$ <b>cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p</b>
.globl foobar
        .type   foobar, @function
foobar:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
#APP
# 15 "asmtest.c" 1
        mov 8(%ebp), %eax
        add $6, %eax
        sub $2, %eax
        mov %eax, -4(%ebp)
# 0 "" 2
#NO_APP
        movl    -4(%ebp), %eax
        leave
        ret
        .size   foobar, .-foobar

Компилятор решил использовать расположение стека num и result напрямую. Если бы мы использовали :"=r":"r" ограничения (что означает, что разрешены только регистры) вместо :"=g":"g" (что разрешает регистры или ячейки памяти), компилятор скопировал бы их в / из регистров до / после встроенной сборки.

$ <b>cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p</b>
.globl foobar
        .type   foobar, @function
foobar:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movl    8(%ebp), %edx
#APP
# 15 "asmtest.c" 1
        mov %edx, %eax
        add $6, %eax
        sub $2, %eax
        mov %eax, %edx
# 0 "" 2
#NO_APP
        movl    %edx, -4(%ebp)
        movl    -4(%ebp), %eax
        leave
        ret
        .size   foobar, .-foobar

Если вы действительно хотите использовать синтаксис Intel, поместите его в отдельный исходный файл .s, соберите его независимо с помощью NASM , затем свяжите объекты вместе.

$ <b>cat asmtest.c</b>
#include <stdio.h>

int foobar(int);
/* int foobar(int) __attribute__((fastcall)); */

int main() {
    int n = 0;
    printf("Number: ");
    scanf("%d", &n);
    printf("%d\n", foobar(n));
    return 0;
}
$ <b>cat foobar.s</b>
global foobar
foobar:
        mov eax,[esp+4]  # take this line out if C prototype is marked fastcall
        sub eax,110b
        add eax,2
        ret
$ <b>nasm -f elf foobar.s</b>
$ <b>cc -m32 asmtest.c foobar.o</b>
$ <b>./a.out</b>
Number: <b>30</b>
26

(Хотя -f elf не подходит для Windows. Может быть -f win32? А из-за глупости Windows вам может понадобиться использовать имя _foobar в сборке.)

...