内联汇编
在c语言中使用汇编代码,为了实现更高效率或执行特定汇编指令。
语法格式
asm volatile("assembly code" |
asm和volatile
- asm 是内联汇编的关键字。
- volatile 关键字告诉编译器不要优化这段汇编代码。
输出操作数
格式为 :[constraints](C variable) constraints 是约束字符串,定义了输出操作数的类型和位置。 (C variable)是 C 变量,用于存储汇编代码的输出。
输入操作数
同输出操作数列表的损坏寄存器
这是一个可选部分,列出了在汇编代码中被修改的寄存器,告知编译器这些寄存器在汇编代码后可能包含不同的值。
e.g.
:
|
这个例子中将a
的值赋值给b
并且打印输出了b
的值。
constraints 约束字符串
约束字符与约束字符不可以连用,但约束字符和约束修饰符可以连用。
约束字符
r
表明通用寄存器,编译器可以选择任意一个通用寄存器来存储操作数。m
表示内存地址,操作数必须是内存位置。i
表示立即数,操作数必须是立即数。
约束修饰符
=
表示输出操作数,所操作的操作数可写。+
表示可读可写,所操作的操作数可读可写。&
该操作数要独占相应的寄存器,不要再将其分配给别人。
匹配约束
匹配约束使用数字来表示操作数与另一个操作数相同,使用这个约束时,两个操作数将使用相同的寄存器或内存地址。
e.g.
:
asm volatile("mv %0, %1" : "=r"(a) : "0"(b)); |
在这段代码中,表示a
和b
使用相同的寄存器。
符号名
在内联汇编中,可以使用别名(也称为符号名)来提高代码的可读性。别名允许你为操作数指定一个更具描述性的名称,而不是依赖数字占位符(如 %0、%1 等)。
格式如下:
asm volatile( |
在使用时,%(符号名)
来进行调用。
e.g.
:
asm volatile("mv %(a), %(b)" : [a]"=r"(a) : [b]"0"(b)); |
list of clobbered registers
在 GCC 内联汇编中,clobbered registers
列表用于告诉编译器在执行内联汇编代码时会修改哪些寄存器。编译器会确保这些寄存器的值在汇编代码执行前被保存,并在汇编代码执行后恢复。这对于避免意外的寄存器值变化和潜在的错误非常重要。
e.g.
:
|
在这段代码当中,防止t0被修改(实际根本不会被修改),写入了clobbered
寄存器当中,在执行完汇编代码之前,会保存t0
寄存器,执行之后,会恢复t0
寄存器。
memory
如果你在clobbered
加入memory
这个特殊的描述符,用于告诉编译器,汇编代码会对内存进行读写操作,可能会影响到内存中的任何数据。这会让编译器知道,它不能依赖于寄存器中的数据,并且需要在汇编代码执行前将所有变量值刷新到内存中,以及在汇编代码执行后重新加载这些变量值。
当你使用 memory
作为 clobbered
描述符时,你告诉编译器以下几点:
输入操作数和输出操作数:编译器会确保在执行汇编代码之前,将所有输入操作数的值刷新到内存中,并在执行汇编代码后,从内存中重新加载所有输出操作数的值。
防止优化:编译器不会对涉及内存的指令进行重排序,因为它不能确定内联汇编代码具体修改了哪些内存地址。这有助于防止潜在的优化问题。