在程序需要在嵌入式平台上运行时,如果需要代码占用内存更小、程序运行的效率更高或需要准确地操作寄存器时,嵌入汇编会是不错的选择。
内嵌汇编的语法格式
asm volatile( /* volatile : 可选,禁止编译器对汇编代码进行优化 */
"汇编指令" /* 汇编指令间使用'\n'分隔 */
:"=限制符"(输出参数)
:"限制符"(输入参数)
:保留列表
)
常用的限制符
限制符 | 说明 |
---|---|
r | 通用寄存器 |
a | eax, ax, al |
b | ebx, bx, bl |
c | ecx, cx, cl |
d | edx, dx, dl |
S | esi, si |
D | edi, di |
q | 寄存器:a、b、c、d |
m | 使用合法内存代表参数 |
g | 任意寄存器、内存、立即数 |
示例代码
下面示例演示的使用汇编对一个变量赋值:
#include <stdio.h>
/* 赋值 */
static int value_assignment(int input) {
int ret = 0;
asm volatile(
/* ret = input */
"movl %1, %0\n" /* 通过占位符指定交互的变量 : %0:ret %1:input*/
:"=r"(ret)
:"r"(input)
);
return ret;
}
int main() {
int input = 1;
int ret = value_assignment(input);
printf("input = %d\n", input);
printf("ret = %d\n", ret);
return 0;
}
打印结果:
input = 1
ret = 1
对于上述示例,编译器做了如下工作:
- 将
ret
通过限定符建议关联到某个合适的寄存器(可以不关联)。 - 将
input
限定符建议关联到另一个合适的寄存器(可以不关联)。 - 通过 通用寄存器 间接操作变量。
下面是 value_assignment()
函数使用 objdump
反汇编的结果:
static int value_assignment(int input) {
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 89 7d ec mov %edi,-0x14(%rbp) /* input */
int ret = 0;
1154: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) /* ret = 0 */
asm volatile(
115b: 8b 45 ec mov -0x14(%rbp),%eax /* 将栈上的 input 变量传递到 eax 寄存器 */
115e: 89 c0 mov %eax,%eax
1160: 89 45 fc mov %eax,-0x4(%rbp) /* eax 寄存器 的值传递到 栈上的 ret 变量 */
"movl %1, %0\n"
:"=r"(ret)
:"r"(input)
);
return ret;
1163: 8b 45 fc mov -0x4(%rbp),%eax
}
1166: 5d pop %rbp
1167: c3 retq
可以看出编译做了优化,没有将 ret
和 input
根据限定符的建议关联到寄存器中,而是直接通过 通用寄存器 与 内存 完成赋值操作。
小结
- C程序中支持直接嵌入汇编语言进行编程。
- 通过寄存器到变量的关联完成汇编到C语言的交互。
- 内嵌汇编代码时,通过占位符指定交互的变量。
- 限制符指示编译器将合适的寄存器关联到变量。(非强制)