asm();括号里面每条指令后不加上\n\t会怎么样
例如下面的代码exam_x86.c
int main()
{
__asm__("cld\n\t"
"cld\n\t"
);
return 0;
}
内核完全注释上说是为了预处理时候对齐指令的,这个说法其实不对,gcc -E选项编译完,还是源程序这个样子
book@book-desktop:~/sgy/first_video/exam/inline_asm$ gcc -E exam_x86.c
# 1 "exam_x86.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "exam_x86.c"
int main()
{
__asm__("cld\n\t"
"cld\n\t"
);
return 0;
}
可见预处理没有处理,使用-S选项停在汇编程序阶段应该能够看出来差别,这里我们将第一行cld的/n/t去掉
gcc -S exam_x86.c
生成的汇编文件---exam_x86.s程序的源码
.file "exam_x86.c"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
#APP
# 3 "exam_x86.c" 1
cldcld
# 0 "" 2
#NO_APP
movl $0, %eax
popl %ebp
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
.section .note.GNU-stack,"",@progbits
从这里看出来你不加上的话,就变成一条cldcld指令,编译的时候就会提示你没有cldcld这条指令
# 3 "exam_x86.c" 1
cldcld
那么第二行的cld需不需要加呢?试验一下就知道了.貌似是可以不加的,当然,到这里我们已经了解到这个在前面几个指令是必须加上的,所以干脆全部加上,保险起见..
结论:
\n是为了让指令分开,不被解析成一条指令,而\t选项是为了对齐好看的.
ret指令
不带任何参数时,用于在子程序的结束位置,被调用的子程序必须有ret指令,否则调用没有ret指令的子程序会导致自陷,子程序执行完之后处于失控状态。带参数ret n 表示子程序返回主程序的同时,堆栈弹出n个字节(栈顶指针减n)
rep指令的目的是重复其上面的指令.ECX的值是重复的次数.
cld相对应的指令是std,二者均是用来操作方向标志位DF(Direction Flag)。cld使DF 复位,即是让DF=0,std使DF置位,即DF=1.这两个指令用于串操作指令中。通过执行cld或std指令可以控制方向标志DF,决定内存地址是增大(DF=0,向高地址增加)还是减小(DF=1,向地地址减小)。
王爽的书
11.10 DF标志和串传送指令
LODS (Load string)串装入指令:将数据从内存指定位置装入CPU中的累加器
指令格式有3种:
LODS OPRD ;OPRD为源串
LODSB
LODSW
LODS指令把由DS:SI指向的源串中的字节或字取到累加器AL或AX中,并在这之后根据DF的值自动修改指针SI,以指向下一个要装入的字节或字。
指令名称:存串指令
用法:stos dst,dst是一个目的地址
【指令格式】STOS 目的串
STOSB ; 存字节串
STOSW ;存字串
stos指令的含义是:将寄存器(AX,EAX)里的内容(一个字或一个字节)存储(store)到内存单元(地址ES:DI),同时CPU自动修改DI,以指向下一元素,即:((DI))←(AX或AL),(DI)←(DI)±1或2。[1]作为参考,与之反操作的指令是lods,它的含义是将内存单元(地址:DS:SI)中的内容装入(load)到寄存器(AX,EAX)。
stos根据操作单元的大小有几种方式byte/word/dword等
SCAS指令用于搜索一个特定的字符或字符串中的字符集。要搜索的数据项应该是在AL,AX(SCASW)或EAX寄存器(SCASD)的(SCASB)。被搜索的字符串应该是在内存中,并指出由ES:DI(或EDI)寄存器。
lea指令(类似offset指令) 当前esp的寄存器值为0x28ff00
lea 0x18(%esp),%eax
执行完eax = 0x28ff18
AT&T汇编enter指令和leave指令
enter指令
在AT&T汇编中,enter等效于以下汇编指令:
pushl %ebp # 将%ebp压栈
movl %esp %ebp # 将%esp保存到%ebp, 这两步是函数的标准开头
leave指令
在AT&T汇编中,leave等效于以下汇编指令:
movl %ebp, %esp
popl %ebp
call指令
在AT&T汇编中,call foo(foo是一个标号)等效于以下汇编指令:
pushl %eip
movl f, %eip
ret指令
在AT&T汇编中,ret等效于以下汇编指令:
popl %eip
movl指令
l是长字(4字节),
w是双字
b是一个字节
加在指令的后边
相当于intel中的
dword ptr
word ptr
byte ptr
int指令
❑ EAX contains the system call value.
❑ EBX contains the file descriptor to write to.
❑ ECX contains the start of the string.
❑ EDX contains the length of the string
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
To access these kernel functions, you must use the int instruction code, which generates a software interrupt, with a value of 0x80.
The specific function that is performed is determined by the value of the EAX register. Without this kernel function,
越是最后入栈,它越是靠近c函数参数左侧
jmpi指令
jmpi go,INITSEG jmpi为段间跳转指令 执行这条指令之后 CS = INITSEG IP = go 也就是跳转到地址 INITSEG : go……
int 0x13指令
入口参数:
AH=02H 指明调用读扇区功能。
AL 置要读的扇区数目,不允许使用读磁道末端以外的数值,也不允许使该寄存器为0。
CH 磁道号的低8位数。
CL 低5位放入所读起始扇区号,位7-6表示磁道号的高2位。cl=开始扇区(位0—5),磁道号高二位(位6—7)
DL 需要进行读操作的驱动器号。dl=驱动器号(若是硬盘则要置位7)
DH 所读磁盘的磁头号。dh=磁头号
es:Bx—>指向数据缓冲区 ES:BX 读出数据的缓冲区地址。
若出错则CF示志置位
返回参数:
如果CF=1,AX中存放出错状态。读出后的数据在ES:BX区域依次排列
jnc指令
JNC Jump if not carry CF=0
STI(Set Interrupt) 中断标志置1指令 使 IF = 1;
CLI(Clear Interrupt) 中断标志置0指令 使 IF = 0.
它们只影响本指令指定的标志,而不影响其他标志位(即STI和CLI只影响IF)。
1、 JNE指令/JNZ功能
条件转移指令JNE/JNZ //不等于转移
格式: JNE/JNZ 标号
功能: ZF=0,转至标号地址处执行
xor指令
xor ax,ax ===>ax = ax 异或 ax
这里进行的是清0操作
lidt指令 加载中段描述符表寄存器IDTR,把IDT表的基地址和长度从内存加载到IDTR中
IDTR,GDTR,TR,LDTR
lmsw指令 加载机器状字(对应CR0寄存器15-0)
LEA reg,mem
mem有效地址->reg
LDS reg,mem
mem低字->reg,mem高字->ds
LES reg,mem
mem低字->reg,mem高字->es
LFS reg,mem
mem低字->reg,mem高字->fs
LGS reg,mem
mem低字->reg,mem高字->gs
LSS reg,mem
mem低字->reg,mem高字->ss
7.28 .fill repeat , size , value
repeat, size 和value都必须是纯粹的表达式。本命令生成size个字节的repeat个副本。
Repeat可以是0或更大的值。Size 可以是0或更大的值, 但即使size大于8,也被视作8,以
兼容其它的汇编器。各个副本中的内容取自一个8字节长的数。最高4个字节为零,最低的
4个字节是value,它以as正在汇编的目标计算机的整数字节顺序排列。每个副本中的size
个字节都取值于这个数最低的size个字节。再次说明,这个古怪的动作只是为了兼容其他
的汇编器。
size参数和value参数是可选的。如果不存在第2个逗号和value参数,则假定value为零。
如果不存在第1个逗号和其后的参数,则假定size为1。
loop指令的格式是:loop标号,cpu执行loop指令的时候,要进行两步操作
1:(cx)=(cx)-1
2:判断cx中的值,不为零则转至标号处执行,如果为零,则向下执行
JE ;等于则跳转
JNE ;不等于则跳转
JZ ;为 0 则跳转
JNZ ;不为 0 则跳转
JS ;为负则跳转
JNS ;不为负则跳转
JC ;进位则跳转
JNC ;不进位则跳转
JO ;溢出则跳转
JNO ;不溢出则跳转
JA ;无符号大于则跳转
JNA ;无符号不大于则跳转
JAE ;无符号大于等于则跳转
JNAE ;无符号不大于等于则跳转
JG ;有符号大于则跳转
JNG ;有符号不大于则跳转
JGE ;有符号大于等于则跳转
JNGE ;有符号不大于等于则跳转
JB ;无符号小于则跳转
JNB ;无符号不小于则跳转
JBE ;无符号小于等于则跳转
JNBE ;无符号不小于等于则跳转
JL ;有符号小于则跳转
JNL ;有符号不小于则跳转
JLE ;有符号小于等于则跳转
JNLE ;有符号不小于等于则跳转
JP ;奇偶位置位则跳转
JNP ;奇偶位清除则跳转
JPE ;奇偶位相等则跳转
JPO ;奇偶位不等则跳转
test指令,测试指令
格式:TEST Dest, Src
实现源操作数于目的操作数的按位逻辑与运算,并按结果设置标志位。但是结果不送入目的地址中。即只作(SRC)^(DEST)。结果影响SF、ZF、PF
例如:测试AL中第3位状态,则使用TEST AL,03H。若ZF=1,表示该位是0;反之,该位是1。
repne,repe指令
lsll指令
lsll 是加载段界限的指令,把 segment 段描述符中的段界限字段装入__limit,函数返回__limit 加 1,即段长。
5.2.6 位操作指令
2、位检测指令(Bit Test Instruction)
指令的格式:BT/BTC/BTR/BTS Reg/Mem, Reg/Imm ;80386+受影响的标志位:CF
位检测指令是把第一个操作数中某一位的值传送给标志位CF,具体的哪一位由指令的第二操作数来确定。
根据指令中对具体位的处理不同,又分一下几种指令:
BT:把指定的位传送给CF;BTC:把指定的位传送给CF后,还使该位变反;BTR:把指定的位传送给CF后,还使该位变为0;BTS:把指定的位传送给CF后,还使该位变为1;
图5.11 位检测指令的功能示意图
例如:假设(AX)=1234H,分别执行下面指令。
BT AX, 2 ;指令执行后,CF=1,(AX)=1234h
BTC AX, 6 ;指令执行后,CF=0,(AX)=1274h
BTR AX, 10 ;指令执行后,CF=0,(AX)=1234h
BTS AX, 14 ;指令执行后,CF=0,(AX)=5234h