1 C语言中的内嵌汇编初体验
内嵌汇编示例
注意:上图中的输出变量,不管是否对其进行操作,最终其所对应的寄存器的值都会保存到这个变量中,所以有时候会出现并没有对输出变量进行操作而输出变量被修改成了一个莫名其妙值的情况。之所以值是莫名其妙的,是因为有些寄存器的值是脏的。
编译器做了什么?
将result关联到某个合适的寄存器(注意这里只是建议,编译器并不一定真的会将result关联到具体的寄存器。但是绝大多数都会关联到寄存器,所以会出现上述寄存器的值为脏的情况)。
将input关联到另一个合适的寄存器(会把input的值读入到相关联的寄存器中)。
通过通用寄存器间接操作变量。
常用限制符的说明
内嵌汇编初体验
#include <stdio.h>
int main()
{
int result = 0;
int input = 1;
int a = 1;
int b = 2;
asm volatile (
"movl %1, %0\n"
: "=r"(result)
: "r"(input)
);
printf("result = %d\n", result);
printf("input = %d\n", input);
asm volatile (
"movl %%eax, %%ecx\n"
"movl %%ebx, %%eax\n"
"movl %%ecx, %%ebx\n"
: "=a"(a), "=b"(b)
: "a"(a), "b"(b)
);
printf("a = %d\n", a);
printf("b = %d\n", b);
return 0;
}
2 深入体验内嵌汇编
问题:如何在不使用printf()的情况下打印字符串?
通过INT 80H使用内核服务:
INT指令用于使用Linux内核服务(中断指令)。
80H是一个中断向量号,用于执行系统调用。
如何指定具体的系统调用(如:sys_write)以及调用参数?
通过寄存器指定具体的系统调用及参数。
INT 80H使用示例一
INT 80H使用示例二
注意事项
嵌入汇编时,除汇编模板外,其余参数可以全部省略。
当省略的参数在中间时,对应分隔符“:”不可省略。
当省略保留列表时,对应分隔符“:”可省略。
当省略可选参数时,寄存器前使用单个%作为前缀。
当存在可选参数(包括输出参数、输入参数、保留列表)时,寄存器前使用两个%作为前缀。
深入体验内嵌汇编
#include <stdio.h>
int main()
{
char* s = "D.T.Software\n";
int l = 13;
printf("main begin\n");
asm volatile(
"movl $4, %%eax\n"
"movl $1, %%ebx\n"
"movl %0, %%ecx\n"
"movl %1, %%edx\n"
"int $0x80 \n"
:
: "r"(s), "r"(l)
: "eax", "ebx", "ecx", "edx"
);
asm volatile(
"movl $1, %eax\n"
"movl $42, %ebx\n"
"int $0x80 \n"
);
printf("main end\n");
return 0;
}
如果不存在可选参数时可以使用(%eax)访问eax所保存地址值的内存,如果存在可选参数则应该使用(%%eax)这种形式。
echo $?可以用来打印上一个刚刚结束的进程的退出码。
3 小结
C程序中支持直接嵌入汇编语言进行编程。
通过寄存器到变量的关联完成汇编到C语言的交互。
内嵌汇编代码时,通过占位符指定交互的变量。
限制符指示编译器将适合的寄存器关联到变量。
通过内嵌汇编能够直接使用系统服务。