2

再一次,我使用 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:”

这里有什么问题?我认为我的代码已经有效?

4

1 回答 1

1

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获取 alias %0"=g"向 GCC 指示%0可以是任何通用寄存器或内存,并且只会被写入。(+而不是=表示读写。GCC 可能会决定将同一个寄存器用于多种目的,因此您必须明确告诉它所有内容将如何使用。)

第二个冒号之后是逗号分隔的输入操作数列表。因为"g" (num)是第二个约束,所以num获取 alias %1"g"意味着它只会被读取。

第三个冒号之后是逗号分隔的 clobbers 列表。这告诉 GCC 内联程序集可能会更改这些寄存器/内存,即使它们不是输入也不是输出,因此 GCC 必须重新加载它通过内联程序集保存在其中的任何信息。在这里,我们显然改变%eax了,条件码(标志)寄存器也受到了影响add/sub

查看编译器生成的程序集:

$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p
.globl foobar
        .type foobar, @function
富吧:
        推%ebp
        movl %esp, %ebp
        低于 $16, %esp
#应用程序
# 15 "asmtest.c" 1
        mov 8(%ebp), %eax
        添加 $6, %eax
        低于 $2, %eax
        mov %eax, -4(%ebp)
#0“”2
#NO_APP
        movl -4(%ebp), %eax
        离开
        ret
        .size foobar, .-foobar

编译器决定直接使用 和 的堆栈num位置result。如果我们使用:"=r":"r"约束(这意味着只允许寄存器)而不是:"=g":"g"(允许寄存器或内存位置),编译器将在内联汇编之前/之后将它们复制到寄存器中/从寄存器中复制它们。

$ cc -S -o- -m32 asmtest.c | sed -n /globl.foobar/,/-foobar/p
.globl foobar
        .type foobar, @function
富吧:
        推%ebp
        movl %esp, %ebp
        低于 $16, %esp
        movl 8(%ebp), %edx
#应用程序
# 15 "asmtest.c" 1
        移动 %edx, %eax
        添加 $6, %eax
        低于 $2, %eax
        移动 %eax, %edx
#0“”2
#NO_APP
        movl %edx, -4(%ebp)
        movl -4(%ebp), %eax
        离开
        ret
        .size foobar, .-foobar

如果您真的想使用 Intel 语法,请将其放在单独的.s源文件中,使用NASM独立组装,然后将对象链接在一起。

$猫 asmtest.c
#include <stdio.h>

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

int main() {
    诠释 n = 0;
    printf("编号:");
    scanf("%d", &n);
    printf("%d\n", foobar(n));
    返回0;
}
$猫foobar.s
全局 foobar
富吧:
        mov eax,[esp+4] # 如果 C 原型标记为 fastcall,则去掉这一行
        子 eax,110b
        添加 eax,2
        ret
$ nasm -f elf foobar.s 
$ cc -m32 asmtest.c foobar.o 
$ ./a.out
数量:30
26

(虽然-f elf对于 Windows 来说不正确。也许-f win32吧?而且由于 Windows 的愚蠢,您可能不得不_foobar在程序集中使用该名称。)

于 2010-02-27T05:40:14.863 回答