扩展内联汇编 __asm__

1:汇编的结构

__asm__ __volatile__(assembly template \\汇编指令行

        : output operand list \\输出操作数列表

        : input operand list \\输入操作数列表

        : clobber list \\破坏列表

内联汇编在逻辑上总是由四部分组成:

  1. 关键字 asm() 或 asm()。修饰符 volatile 或 volatile:关键字 asm 或 asm 用于说明随后的字符串是内联汇编代码块。volatile 或 volatile 是可选的,可以将它们添加到 asm 后面,禁止某些编译器的优化。其实,asm 和 __asm__几乎是相同的,惟一的区别是,当预处理程序宏中使用内联汇编时,asm 在编译过程中可能会引发警告。volatile 和 volatile 也是如此。

  2. 汇编模板:
    汇编模板是括号内的第一个部分。它包含汇编指令行,这些指令行都包括在双引号 (“”) 中,以行分隔符(\n\t 或 \n)结束。内联汇编代码的语法是相同的,但比一般的汇编代码简单得多。这其中有许多原因。例如,它不需要在汇编模板中定义数据,因为它应该始终从 C/C++ 变量引用。而且,很少有必要在汇编模板中(为可执行文件)创建一个分段。一般情况下,除了汇编指令,只允许使用一些本地标签。

#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
	: "=a" (__res) \          //输出参数放到__res中
	: "0" (__NR_##name)); \   //输入参数__NR_name代表的值
if (__res >= 0) \
	return (type) __res; \
errno = -__res; \
return -1; \
}

这段代码的大体含义:触发0x80中断,进入系统调用,具体的调用函数是__NR_name代表的函数。函数返回结果会在eax中,并把eax寄存器的值(返回值) 赋值给__res

汇编指令行
一个指令的操作数是寄存器/立即类型的操作数,那么可以引用它作为一个带有百分比前缀编号的寄存器。 (%0, %1,…)

输出操作数列表
" " 中的值是可选约束修饰符
例如,=&r (ret) 的修饰符是 = 和 &。= 表示该变量是只写的。& 表示这个变量不能与任何输入操作数共享相同的寄存器。

参考: 汇编相关介绍

在这里插入图片描述

2: repne scasb

unsigned long get_free_page(void)
{
register unsigned long __res asm("ax");

__asm__("std ; repne ; scasb\n\t" //遍历字节数组位置(edi)从后向前,直到找到为al(0)的字符。ecx 每次减1,进行计数为0的字符所在的位置 
	"jne 1f\n\t" //没有等于0的字节,就跳转结束,返回0
	"movb $1,1(%%edi)\n\t" // edi + 1 = 1, 对数组对应的的字节置1 
	"sall $12,%%ecx\n\t" //ecx是当前页的位置,乘以4K,获取 相对 页面起始的地址 。 (页面再1M之后开始算计第0个页,所以这个计算的地址离最开始的物理地址还差1M)
	"addl %2,%%ecx\n\t" //ecx加上 %2 (LOW_MEM),就变成了 相对于物理地址起始的 地址,就是真正的物理地址。
	"movl %%ecx,%%edx\n\t"// 把物理地址赋值给edx
	"movl $1024,%%ecx\n\t" //把ecx变成1024  why ?
	"leal 4092(%%edx),%%edi\n\t" //edi = edx + 4092, edi指向页的最后一个地址
	"rep ; stosl\n\t"   //把整页内存清0 ,从edi开始,从后向前。 req要用的寄存器是edi,所以要给edi赋值要操作的的值。又因为从后向前,所以edi的地址要指向最后一个。
	"movl %%edx,%%eax\n" //把物理地址edx 赋值给 eax 用来返回。
	"1:"
	:"=a" (__res) //把返回值eax的值,赋值给变量__res
	:"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES), //al = 0, xx = LOW_MEM  ecx = PAGING_PAGES(页总数)
	"D" (mem_map+PAGING_PAGES-1) //edi = mem_map+PAGING_PAGES-1, mem_map是数组的起始地址,加上总长度PAGING_PAGES,再减1。就变成了数据的最后一个元素
	:"di","cx","dx");
return __res;
}

repne:rep指令重复其后指定的字符串操作指令,重复的次数由计数寄存器cx来决定
scasb:用来搜索字符
一些标志位参数:
DF:方向
CX:所要搜索的串的长度
ax:所要搜索的数据
di:所要搜索的那条串串

std repne ; scasb
扫描edi指向的字符串,扫描方向从低位地址向高位地址,如果遇到字节等于al或者ecx计数为0,则结束扫描

其中
edi 指的是 “D” (mem_map+PAGING_PAGES-1) 中 mem_map+PAGING_PAGES-1 就是数组中的最后一个字符。
al 指的是 “0” (0)

所以上面这句话意思就是,从mem_map数组中最后一个字节向前扫描,知道遇到字节为0 或者 ecx计数变为0 终止

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值