1.Syntax
Register Reference
Operator Sequence
movl %eax,%ebx 从左到右 左边为源 右边为 目的操作数
Immediately Operator
立即数前面加上符号 eg:movlor:para=0x04movl para,%ebx
Symbol Constant
符号常数直接引用eg:
value: .long 0x12a3f2de
movl value,%ebx
如果写成movl $value,%ebx 则是将符号value的地址装入寄存器ebx
Length of Operator
b:byte w:word l:long
如果没有制定操作数的长度的话,编译器将按照目标操作数的长度来设置。 eg:
movb %al,%bl
mov 4,对于没有制定操作数长度又无法猜测长度的指令,将会报错。eg:push 4
Sign and Zero Extension
在AT&T语法中,基本部分movs/movz(intel为movsx movzx)后面跟上源操作数的长度和目的操作数的长度。eg:
movsbl: movs from byte to long
而对于intel来说还有其他的符号扩展指令:cbw,cwde,cwd,cdq
Call and Jump
段内调用和跳转指令为 call ret jmp
段间调用和。。。。为 lcall lret ljmp 格式为:
lcall/ljmp SECTION, OFFSET
lret $STACK-ADJUST
Prefix:
字符串重复操作指令 rep repne
指定被操作的段 cs ds ss es fs gs
进行总线加锁 lock
指定地址和操作的大小 data16 addr16
eg:
repne
scas
Memory Reference
Intel语法间接内存引用的格式为:
section:[base+index*scale+displacement]
AT&T:
section:displacement(base,index,scale)
eg:
-4(%ebp): base=%ebp,section=ss index=0
foo(,%eax,4) index=%eax base=0 section=%ds
foo(,1): 这个表达式引用的是指针foo指向的地址所存放的值。
%gs:foo 表达式引用的是放置于%gs段里变量foo的值
如果call和jump操作在操作数前指定前缀* 则表示是一个 绝对地址调用/跳转。 否则操作数是一个相对地址。
任何指令如果其操作数是一个 内存操作,则指令必须指定它的操作尺寸。
2.gcc Inline ASM
2.1 Essential Inline ASM
__asm__("movl %esp,%eax");
or
__asm__("
movl $1,%eax
xor %ebx,%ebx
int $0x80
");
or:
___asm__(
"movl $1,%eax\r\t"
"xor %ebx,%ebx\r\t"
"int $0x80"
);
基本的内联汇编格式 asm __volatile(“Instruction List”);
1.asm
是GCC关键字asm的宏定义
define __asm__ asm
2.Instruction List
__asm__("":::memory");
表示我对内存进行了改动。
内嵌汇编的指令的原则可以总结为:
- 任意两个指令要么被分号分开,要么被放在两行
- 放在两行的方法既可以从过\n的方法实现,也可以真正的放在两行;
- 可以使用1对或者多对引号,每对引号里面可以放任一多条指令,所有的指令都要放到引号中。
volatitle是gcc的关键字volatile的宏定义
#define __volatitle__ volatitle
它的作用是向GCC声明 不要改动我们写的Instruction List,否则当使用-o进行编译是,GCC将会自己觉得是否需要进行优化。
2.2 Inline ASM with C/C++ Expression
带有C/C++表达式的内联汇编格式位
“`
asm volatitle(“Instruction List”
:output
: Input
:Clobber/Modify
);
1.output
__asm__("movl %%cr0,%0":"=a" (cr0));
=表示输出 +表示输入和输出
Output域可以有多个输出表达式,但中间要用逗号分开
2.Input
Input域的内容用来指定当前内联汇编的语句的输入
__asm__("movol %0,%%db7": : "a" (cpu->db7));
3.Operation Constraint
每一个Input和Output表达式都必须指定自己的操作约束。
这里讨论在386平台上所可能使用的操作约束。
3.1 Register Constraint
当输入需要借助一个寄存器的时候,需要为其指定一个寄存器约束。可以直接指定寄存器的名字
__asm__ __volititle__("movl %0,%%cr0"::"eax"(cr0));
3.2 Memory Constraint
如果一个Input/Output 操作表达式表现位一个内存地址,不像借助与任何一个寄存器 则可以使用内存约束。eg:
__asm__ ("lidt %0":"=m"(__idt_addr));
对于c++内联汇编理解不够深入。以后再进行学习。