概述
《Linux0.11内核完全注释》读书笔记
嵌入汇编
asm("汇编语句":输出寄存器
:输入寄存器
:会被修改的寄存器);
kernel/traps.c文件中第22行开始的一段代码作为例子。
#define get_seg_byte(seg,addr) ({
register char __res; //定义了一个寄存器变量__res。
__asm__("push %%fs; //首先保存fs寄存器原值(段选择符)。
mov %%ax, %%fs; //然后用seg设置fs。
movb %%fs:%2, %%al; //取seg:addr处1字节内容到al寄存器中。
pop %%fs" //恢复fs寄存器原内容。
:"=a" (__res) //输出寄存器列表
:"0" (seg), "m" (*(addr))); //出入寄存器列表__res;
})
这段10行代码定义了一个嵌入汇编语言宏函数。通常使用汇编语句最方便的方式是把它们放在一个宏内。用圆括号括住的组合语句(花括号中的语句):“({})”可以作为表达式使用,其中最后一行上的变量__res(第10行)是该表达式的输出值。
再看一个简单的例子。
asm("cldnt"
"repnt"
"stol":/*没有输出寄存器*/
:"c"(count-1), "a"(fill_value),"D"(dest)
:"%ecx", "%edi");
常用寄存器加载代码说明
代码
说明
代码
说明
a
使用寄存器eax
m
使用内存地址
b
使用寄存器ebx
o
使用内存地址并可以加偏移值
c
使用寄存器ecx
I
使用常数0-31
d
使用寄存器edx
J
使用常数0-63
S
使用esi
K
使用常数0-255
D
使用edi
L
使用常数0-65535
q
使用动态分配字节可寻址寄存器(eac、ebx、ecx或edx)
M
使用常数0-3
r
使用任意动态分配的寄存器
N
使用1字节常数(0-255)
g
使用通用有效的地址即可(eax、ebx、ecx、edx、或内存变量)
O
使用常数0-31
A
使用eax与edx联合(64位)
=
输出操作数。输出值将替换前值
+
表示操作数可读可写
&
早期会变的(earlyclobber)操作数,表示在使用完操作数之前,内容会修改
关键词volatile也可以放在函数名前来修饰函数,用来通知gcc编译器该函数不会返回。这样就可以让gcc产生更好的一些代码。
volatile void do_exit(long code);static inline volatile void oom(void)
{
printk("out of memorynr");
do_exit(SIGSEGV);
}
圆括号中的组合语句
花括号对”{…}“用于把变量声明和语句组合成一个复合语句(组合语句)或一个语句块,这样在语义上这些语句就等同于一条语句。圆括号中的组合语句,即形如”({…})“的语句,可以在GNU C中用作一个表达式使用。这样就可以在表达式中使用loop、switch语句和局部变量,因此这种形式的语句通常称为语句表达式。
({int y = foo(); int z; if (y>0) z=y; else z = -1; 3+z;})
其中组合语句最和一条语句必须是后面跟随一个分号的表示式。这个表达式(”3+z“)的值即用作整个圆括号括住语句的值。如果最后一条语句不是表达式,那么整个语句表达式具有void类型,因此没有值。另外表达式中声明的局部变量会在语句块结束后失效。这个实例可以像如下形式的赋值语句来使用:
res=x+({...})+b;
当然,一般这种语句表达式通常用来定义宏。例如内核源码init/main.c程序中读取CMOS时钟信息的宏定义:
#define CMOS_READ(addr) ({
outb_p(0x80|addr, 0x70);
inb_p(0x70);
})
再看一个例子在include/asm/io.h中读I/O端口port的宏定义,其中最后变量_v的值就是inb()的返回值。
#define inb(port) ({
unsigned char _v;
__asm__ volatile ("inb %%dx, %%al":"=a" (_v):"d" (port));
_v;
})
最后
以上就是激情柠檬为你收集整理的linux 0.11 内核代码行,linux0.11内核完全注释读书笔记的全部内容,希望文章能够帮你解决linux 0.11 内核代码行,linux0.11内核完全注释读书笔记所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复