在/linux0.11/kernel/trap.c文件中,第一次接触到C语言中的嵌入式汇编代码。详细的运用阐明能够参阅GNUgcc手册中第4章的内容或许参阅文献《using assembly with gcc》。
具有输入和输出参数的嵌入式汇编的根本格局为:
asm(“汇编句子“
asm(”汇编句子“
: 输出寄存器
: 输入寄存器
: 会被修正的寄存器);
其间,”汇编句子“是你写汇编指令的当地;”输出寄存器“表明当这段嵌入汇编履行完之后,哪些寄存器用于寄存输出数据。”输入寄存器“表明在履行汇编代码时,这儿指定的一些寄存器中应该寄存的输入值,他们别离对应着一C变量或许常数值。下面将举例阐明嵌入式汇编的详细因运用方法。
例如1:
这段代码界说了1个嵌入式汇编函数。由于是宏句子,需要在一行上界说,因而这儿运用反斜行‘\’将这些句子连成1行。第1行界说了宏的称号,即宏函数称号为get_seg_byte(seg,addr)。第3行界说了一个寄存器变量_reg 。 第4行上的_asm_表明嵌入汇编句子开端。从第4行到第7行的4条AT&T 格局的汇编句子。
第8行是输出寄存器,这句话的意义是在这段代码运转完毕后将eax所代表的寄存器中的值放入_res 变量中,作为本函数的输出值。为了在上面汇编句子中运用该地址值,嵌入汇编程序规则把输入和输出寄存器统一按次序编号,次序是从输出寄存器序列从左到右从上到下以%0 开端,别离记为%0,%1,%2.。。.%9。因而,输出寄存器编号为%0 输入寄存器前一部分“”(seg)的编号为%1,然后一部分的编号为%2. 上面第6行上的%2代表(*(addr))这个内存偏移量。
现在剖析4-7行上代码的详细效果。第1句将fs段寄存器的内容入栈;第2句将eax中的段值赋给fs段寄存器;第3句是把fs:(*addr))所拟定的字节放入al寄存器。当履行完汇编句子后,输出寄存器eax的值将被放入_res。
通过上面的剖析,咱们知道宏称号中的seg代表一指定的内存段值,而addr表明一内存偏移地址量。到现在为止,咱们应该很清楚这段程序的功用。该宏函数是从指定的段和偏移量的内存地址处取一个字节。
例如2:
1-3行这三句是常用的汇编句子,用以清方向标识位,心胸保存值。第四行阐明没有用到输出寄存器。第5行的意义是将count-1的值将在到ecx寄存器中(加载码是“c“)fill_value 加载到eax中,dest放到edi中。 为什们要让gcc编译程序去做这样的加载,而不让咱们自己做呢?由于gcc在它进行寄存器分配时能够进行某些优化作业。例如fill_value值或许现已加载到eax中。假如在一个循环句子中的话,gcc或许在整个循环操作中保存eax,这样就能够在每次循环中少用1个movl句子。
最终1行是告知gcc这些寄存器中的值现已改变了。很古怪吧?不过,gcc知道你拿这些寄存器做了什么后,这的确能够对gcc的优化操作有所协助。
下面是或许会用的寄存器加载码及其详细意义:
代码 阐明
a 运用寄存器eax
b 运用寄存器ebx
c 运用寄存器ecx
d 运用寄存器edx
S 运用寄存器esi
D 运用寄存器edi
q 运用动态分配字节可寻址寄存器 (eax、ebx、ecx或edx)
r 运用恣意动态分配的寄存器
g 运用通用有用的地址即可(eax、ebx、edx、ecx 或许内存变量)
A 运用eax和edx联合(64bit)
m 运用内存地址
o 运用内存地址,并能够加载偏移值
I 运用常数0-31
J 运用常数0-63
K 运用常数0-255
L 运用常数0-65536
M 运用常数0-3
N 运用1字节常数(0-255)
O 运用常数0-31
下面的比如不是让自己拟定那个变量运用那个寄存器,而是让gcc为你挑选
asm(“leal(%1,%1,4),%0”
:“r”(y)
:“0”(x));
第1句leal(r1,r2,4),r3 句子表明r3=r1+r2&TImes;4。这个比如能够非常快的将x成5.其间“%0”,“%1” 是指gcc主动分配的寄存器。这儿%1 代表输入值x要放入的寄存器,”%0“表明输出寄存器。所以假如gcc将r指定为eax的话,那么上面汇编句子的意义为”leal(eax,eax,4),eax“ 留意 假如不期望汇编句子被gcc优化而移动当地,就需要在asm符号后边增加volaTIle关键字
asm volaTIle();或许
__asm__ __volaTIle__();