GCC内联汇编

本文介绍了GCC内联汇编的基本语法和扩展形式,包括如何插入汇编指令、使用全局变量以及防止编译器优化。重点讲解了扩展ASM的四部分构成:汇编代码、输出位置、输入操作符和改变的寄存器。此外,还详细阐述了操作符的使用,如输入输出变量的定义以及占位符的含义,如`%0`、`%1`等。通过实例展示了内联汇编在处理寄存器和内存单元时的规则和注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GCC内联汇编


1. 基本内联语法:

GCC用关键字asm表示一段用汇编语言写的源代码。形式如下:
asm ("assemble language");
说明:

  1. 汇编指令必须用双引号扩起来
  2. 如果有多条汇编指令,必须用换行符隔开\n,每条语句之前最好加上\t,为了区别汇编语言中的标号label

编译器实际上把asm括号中双引号引起来的语句逐字的插入到编译后产生的汇编文件中.s,并进行了相应的替换操作。
可以这样:

asm ("movl $1,%eax\n\tmovl $0,%ebx\n\tint $0x80");

看起来麻烦,可以分行,分开成多个双引号:

asm ("movl $1,%eax\n\t"
    "movl $0,%ebx\n\t"
    "int $0x80");

可以使用C程序中的全局变量:

#include <stdio.h>

int a = 10;
int b = 20;
int result;

int main(){
    asm("pusha\n\t"
        "movl a, %eax\n\t"
        "movl b, %ebx\n\t"
        "imull %ebx, %eax\n\t"
        "movl %eax, result\n\t"
        "popa");
    printf("the answer is %d\n",result);
    return 0;
}

有时候编译器会对变易产生的汇编代码进行优化,可能导致产生的效果与我们预想的不一样。可以在asm之后使用volatile关键字进行说明,让编译器不进行优化。
Note:如果使用ANSI C标准,asmvolatile都要写成__asm__ __volatile__

2. 扩展的ASM

基本形式有很多限制:输入输出只能使用C语言中的全局变量,而且不能随意地改变寄存器的值。(前面的例子中开头和结尾使用pushapopa来保存寄存器)

扩展汇编形式:
asm (
	"assembly code"
	: output locations
	: input operands
	: changed registers);

这种形式有四个部分,用冒号隔开:

  • 汇编代码assembly code:内联汇编代码,语法同基本asm格式。变量用占位符表示。
  • 输出位置output locations:汇编代码中输出值所在的寄存器和内存单元列表。(执行汇编代码之后)
  • 输入操作符input operands:汇编代码中输入值所在的寄存器和内存单元的列表。(执行汇编代码前处理)
  • 改变的寄存器changed registers:内联汇编代码中改变的寄存器(用于提醒编译器对这些寄存器进行保护操作)。
操作符

在基本asm格式中,汇编语言中输入输出值可以直接使用C语言中的全局变量,但是在扩展asm格式中,格式不太一样:
"constraint"(variable)
variable是一个C语言变量(全局变量或局部变量都可以),constraint定义了从哪里取这个变量(对于输入变量来说)或往哪里存放(对输出变量)。constraint可能的取值如下表:

constraintdescription
ause the %eax,%ax or %al regiters
buse the %ebx,%bx or %bl registers
cuse the %ecx,%cx or %cl registers
duse the %edx,%dx or %dl registers
Suse the %esi or %si registers
Duse the %edi or %di registers
ruse any available general-purpose register
quse either the %eax,%ebx,%ecx or %edx register
Ause the %eax and the %edx regiters for a 64-bit value
fuse a floating-point register
tuse the first(top) floating-point register
uuse the second floating-point register
muse the variable’s memory location
ouse an offset memory location
Vuse a direct memory location
iuse an immediate integer value
nuse an immediate integer value with a known value
guse any register or memory location available

除了这些限制,输出值还包含一个限制修饰符,它指明编译器如何处理输出值。

output modiferdescription
+The operand can be both read from and written to
=The operand can only be written to
%The operand can be switched with the next operand if necessary
&The operand can be deleted and reused before the inline functions c

举例:

asm ("assembly code" : "=a"(result) : "d"(data1),"c"(data2));

这个例子中C变量data1放在%edxdata2放在%ecx。输出结果会被放到%eax,然后送到result变量。

#include <stdio.h>
int main(){
    int data1 = 10;
    int data2 = 20;
    int result;
    
    asm ("imull %%edx, %%ecx\n\t"
        "movl %%ecx, %%eax"
        : "=a"(result)
        : "d"(data1), "c"(data2)
        );
    printf("The result is %d\n",result);
    return 0;
}
asm volatile ("cld\n\t"
        "rep movsb"
        :
        :"S"(input),"D"(output),"c"(length));

由于没有指定输出规则,编译器会认为这段汇编是不必要的,因此要加上volatile

占位符

汇编语言部分assembly language可以使用占位符placeholder用来引用输出输入变量。格式为%0 %1 ...用来表示输出输入列表中的变量。

asm ("imull %1, %2\n\t"
    "movl %2, %0\n\t"
    :"=r"(result)
    :"r"(data1),"r"(data2)
    );

%0代表存放result的寄存器;%1代表存放data1的寄存器;%2代表存放data2的寄存器。

asm ("imull %1,%0"
    : "=r"(data2)
    : "r"(data1),"0"(data2));

"0"表示让编译器使用第一个命名的寄存器。

int dividend = 20 ;
int divisor = 5;
int result ;
asm ("divb %2\n\t"
    "movl %%eax, %0"
    :  "=m"(result)
    : "a"(dividend),"m"(divisor));

内联汇编可以使用标签,用来进行跳转。数字可以作为局部标签。

asm ("cmp %1, %2\n\t"
    "jge 0f\n\t"
    "movl %1, %0\n\t"
    "jmp 1f\n"
    "0:\n\t"
    "movl %2, %0\n"
    "1:"
    :"=r"(result)
    :"r:(a),"r"(b));

0: 1:都是label,jmp 0ff表示forward,如果向后跳转使用b即backward。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值