汇编语言之基础(三 嵌入汇编)

嵌入汇编

  1. 说明:

    用来在c语言中写汇编程序

    汇编语言无法实现内存到内存操作‘

    但是可以实现寄存器到内存的操作

  2. 通用写法:

__asm__ volatile("汇编指令"           必须存在字段
                 : =限制符(输出参数)   这是可选的可以不需要写
             : 限制符(输入参数)    这是可选的可以不需要写
                 : 保留列表
            );

​ 其中volatile代表是否优化,存在代表不允许编译器优化

  1. 汇编搭配宏

    使用汇编语言最常用的方式就是把汇编语言写在宏里,加上({})这种GNU独有的语法,在{}像函数一样进行定义,把最后一个语句作为返回值返回

#define get_value(input, output)  ({ \
    __asm__ volatile("mov %0, %1"        \
                     : "=a"(output)   \
                     : "a"(input)     \
                    );                \
    output;                           \
})
a是限制符,是对参数的说明,对于输入参数来说就是把输入参数放到eax寄存器中
输出参数代表汇编结束把该寄存器内容给到输出参数
通过通用寄存器间接操作变量,汇编语言是操作 寄存器的,不支持直接操作内存
=就是用来区分输入参数
  1. 汇编多指令两种写法:
 __asm__ volatile("mov %0, %1\n"        \
 				  "mov %0, %1\n"        \
                     : "=a"(output)   \
                     : "a"(input)     \
                    );   
每行用换行符分割,作为一行的结束

__asm__ volatile("mov %0, %1;" \
                     "mov %0, %1;"        \
                     : "=a"(output)   \
                     : "a"(input)     \
                    );                \
每行用;分割,作为一行的结束
__asm__ volatile("mov %0, %1; \
                     mov %0, %1;"        \
                     : "=a"(output)   \
                     : "a"(input)     \
                );                \
相当于直接使用一条指令,用\进行连接                           

值得注意的是,在gcc编译嵌入汇编,汇编指令中寄存器访问需要加两个%%

  1. 定义寄存器变量:

    register char ___res; 编译器会为我们分配寄存器

    如果想指定寄存器,那么register char ___res asm(“‘eax’”);

  2. 当使用标号“0”代表使用同上个位置相同的寄存器

  3. 编译器规定把输出输入寄存器统一编号,顺序从输出寄存器序列从左到右从上到下以%0开始,分别记为 %0 %1

  4. 看一下常用的限定符

  5. 关于volatile也可以放在没有返回值的函数前面,volatile void print();这样的好处是明确告诉编译器该函数不会返回,这样就可以让gcc产生更好的代码

	asm volatile ( "movl %%eax, %%ecx\n"
				"movl %%ebx, %%eax\n"
				"mov %%ecx, %%ebx\n"
				 : "=a"(output), "=b"(input)
				 : "a"(output), "b"(input)
	);
	printf("input=%d, output = %d\n", input, output);

​ 汇编交换两个值,注意的是,input output 既可以在输入的地方,也可以在输出的地方

  1. 使用汇编可以做什么?

    在Linux中,应用层想要调用内核层的函数,不能直接调用,需要使用系统调用函数,而调用系统调用的方式就是通过汇编,使用软中断实现,INT 80H , INT是使用Linux内核指令,80H是中断向量号,用于执行系统调用

    fd文件描述符,0代表标准输入,1代表标准输出,2代表异常输出

    代码:

	asm volatile ( 
				"movl $4, %%eax\n"
				"movl $1, %%ebx\n"
				"movl %0, %%ecx\n"
				"movl %1, %%edx\n"
				"int $0x80 \n"
				 : 
				 : "r"(s), "r"(len)
				 : "eax", "ebx", "ecx", "edx"
	);

​ 对于 sys_write这个系统调用,需要%eax寄存器写入4,代表选择sys_write, ebx寄存器代表fd的值,ecx代表字符串指针,edx代表写的个数

​ 注意的是,嵌入式汇编除了汇编模板外,其他参数都可以省略

​ 当省略的参数在中间时,对应分隔符 “:” 不可省略

​ 当省略保留列表时,对应分隔符可以省略

​ 当可选参数被省略,寄存器前使用单个%作为参数

​ 当可选参数不被省略,寄存器前使用两个%%作为参数

更多的系统调用函数请看

参考Linux内核注释

参考狄泰软件门徒计划

posted @ 2020-12-08 22:54  make_wheels  阅读(799)  评论(0编辑  收藏  举报