一、常用指令
1. 通用数据传送指令.
MOV 传送字或字节.
MOVSX 先符号扩展,再传送.
MOVZX 先零扩展,再传送.
PUSH 把字压入堆栈.
POP 把字弹出堆栈.
PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈.
POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈.
PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈.
POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈.
BSWAP 交换32位寄存器里字节的顺序
XCHG 交换字或字节.( 至少有一个操作数为寄存器,段寄存器不可作为操作数)
CMPXCHG 比较并交换操作数.( 第二个操作数必须为累加器AL/AX/EAX )
XADD 先交换再累加.( 结果在第一个操作数里 )
XLAT 字节查表转换.
BX 指向一张 256 字节的表的起点, AL 为表的索引值 (0-255,即 0-FFH); 返回 AL 为查表结果. ( [BX+AL]->AL )
2. 输入输出端口传送指令.
IN I/O端口输入. ( 语法: IN 累加器, {端口号│DX} )
OUT I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )
输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 [...]
【汇编语言】分类文章列表
汇编指令集合|汇编指令大全
C语言生成随机数的函数、延时函数
下面C语言代码使用了生成随机数的函数、延时函数。请大家仔细观察其显示效果。
从以下代码,我们可以得出一个重要的结论:当上述两类函数被放入循环时,应作出一定修改。同时还应关注其参数的定义位置(子函数外?子函数内?全局变量?局部变量?)。
另外大家要注意:scanf在输入double型时,应该使用%lf,而在printf时却只需使用%f.
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
double t_delay;
time_t start,end; //start,end修改后的位置
int createOrNot()
{
int flag;
//srand(time(NULL) );//srand()原先的位置
flag = (int)( (2*rand()/RAND_MAX) +1 );
return flag;//return 1 or 2
//1 create,2 not create.
}
void delay()
{
time_t start,end;//end原先的位置
double dif;
time (&start);
while( (dif= difftime (end,start) )<5000.0 )//注意这里
{
time (&end);
};
}
void delay(time_t end )//end修改后的位置
{
time_t start;//,end;
double dif;
time (&start);
while( (dif= difftime (end,start) )<2.0 )//注意这里
{
time (&end);
};
}
void delay(time_t end,double time_delay)//change…
{
time_t start;//,end;//change…
double dif;
time (&start);
time (&end);
while( (dif= difftime (end,start) ) < time_delay )
{
time [...]
汇编语言程序语句之伪操作
汇编语言程序语句除指令以外还可以由伪操作和宏指令组成.伪操作又称伪指令,它不像机器指令那样是在程序运行期间由计算机来执行的,它是在汇编程序对源程序汇编期间由汇编程序处理的操作,这们可以完成如数据定义、分配存储区、指示程序结束等功能。
一、数据定义及存储器分配伪操作这一类伪操作的格式是:
[Variable] Mnemonic Operand,…,Operand[;Comments] 其中变量(Variable)字段是可有可无的,它用符号地址表示,其作用与指令语句前的标号相同,但它的后面不跟冒号.如果语句中有变量则汇编程序使其记以第一个字节的偏移地址.
注释(Comments)字段用来说明该伪操作的功能,它也是可有可无的. 助记符(Mnemonic)字段说明所用伪操作的助记符,常用的有以下几种: DB伪操作用来定义字节,其后的每个操作数都占有一个字节. DW伪操作用来定义字,其后的每个操作数都占有一个字(低位字节在第一个字节地址中,高位字节在第二个字节地址中).
DD伪操作用来定义双字,其后的每个操作数占有二个字.
DQ伪操作用来定义四个字,其后的每个操作占有四个字.
DT伪操作用来定义十个字节(五个字),其后的每个操作数占有十个字节,形成压缩的BCD码.
操作数字段还可以使用复制操作符(duplication opreator)来复制某个操作数,例: ARRAY1
DB 2 DUP(0,1,2,?) 注1:使用PTR属性操作符,可以指定操作数的类型属性. 例:
MOV
AX,WORD PTR OPER1 注2:使用LABEL伪操作可以使同一变量具有不同的类型属性. 例:
BYTE_ARRAY LABEL BYTE WORD_ARRAY DW 50 DUP(?)
二、表达式赋值伪操作EQU 格式:变量名 EQU 表达式例: CONST EQU 256
数赋以符号名 DATA EQU HEIGHT+12
地址表达式赋以符号名 ALPHA EQU 7 BETA EQU ALPHA-2 B EQU [BP+8]
变址引用赋以符号名B P8 EQU DS:[BP+8] 另有一个与EQU类似的=伪操作也可以作为赋值操作使用.这们之间的区别是EQU伪操作中的表达式名是不允许重复定义的,而=伪操作则允许重复定义. [...]
Linux下的汇编程序设计
Linux汇编简介:
一、汇编语言的优缺点:
由于Linux是用C写的,所以C自然而然的就成为了Linux的标准编程语言。大部分人都把汇编给忽略了,甚至在因特网上找资料都是非常的困难,很多问题都需要靠自己来尝试。我认为这样对待汇编语言是不公平的,不能只看到它的缺点,当然也不能只看到它的优点,下面把它的优缺点作一个比较:
优点:汇编语言可以表达非常底层的东西
l 可以直接存取寄存器和I/O
l 编写的代码可以非常精确的被执行
l 可以编写出比一般编译系统高效的代码
l 可以作为不同语言或不同标准的接口
缺点:汇编语言是一个非常低级的语言
l 非常冗长单调,在DOS下编程时就可以体会到
l 易出BUG,且调试困难
l 代码不易维护
l 兼容性不好,与硬件关系非常紧密
总的来说,汇编语言要用在必须的地方,尽量少用汇编编写大型程序,多采用inline模式。
二、汇编语言工具:
DOS下常用的工具MASM和TASM到Linux下就用不起来了,Linux有自己的汇编工具,而且种类非常的多。其中Gas可以算是标准配置,每一种Linux中都包括有Gas,但是GAS采用的不是我们通常在DOS下采用的汇编语法,它采用的是AT&T的语法格式,与intel语法格式有很大的不同。
如果要采用与DOS接近的语法格式,就必须用另一种汇编工具NASM,NASM基本与MASM相同,但也有不少地方有较大区别,特别涉及到操作系统原理时,与DOS可以说是截然不同。
Linux汇编程序设计:
一、Hello,world!
几乎所有的语言入门篇都是以“Hello,world!”为例,那么我也以Hello,world!为例开始。
;————-NASM’s standalone Hello-World.asm for Linux ——–
section .text
extern puts
global main
main:
push dword msg ;stash the location of msg on the stack.
call puts ;call the “puts” routine (libc?)
add esp, byte 4 ;clean the stack?
ret ;exit.
msg:
db “Hello World!”,0
编译:
nasm –f elf hello.asm
gcc –o hello hello.o
说明:这个程序实际上是调用了,Linux系统的puts函数,原理与调用DOS下C语言的函数相同,先用Extern声明puts是外部函数,再把参数(即msg的地址)压入堆栈,最后Call函数实现输出。
我们再来看一个程序:
section .text
global main
main:
mov eax,4 ;4号调用
mov ebx,1 ;ebx送1表示stdout
mov ecx,msg [...]
掀起硬盘主引导扇区的神秘面纱
硬盘主引导扇区是一个敏感的区域, 它的安全与否直接决定硬盘是否能够正常使用。 深入认识和灵活使用硬盘主引导扇区将有助于你的系统维护和许多特殊工作完成。
一、与DOS 引导扇区的区别
对于DOS系统来说, 有两种不同的引导扇区,即DOS 引导扇区和硬盘主引导扇区。 DOS 引导扇区存在于软盘的第一逻辑扇区或硬盘DOS分区的第一逻辑扇区,是用FORMAT命令对磁盘格式化时产生的, 是引导DOS 系统或正确使用磁盘的必要条件,在DOS下可用DEBUG方便地读出:
C>DEBUG
-L 100 2 0 1
;读C盘0扇区到内存当前段的100H处
-D ;显示DOS 引导扇区内容
硬盘主引导扇区则指的是硬盘的物理地址0 面0 道1 扇区,是用FDISK 进行硬盘分区时产生的, 它属于整个硬盘而不属于某个独立的DOS 分区, 是硬盘正确引导和使用的必要条件。由于它不在DOS分区范围之内,所以无法用上述方法读出, 只有用相关的汇编程序代码读出:
C>DEBUG
-A
XXXX:0100 MOV AX,0201H ;指定扇区数
XXXX:0103 MOV BX,0800H ;指定内存地址
XXXX:0106 MOV CX,0001H ;指定磁道和扇区号
XXXX:0109 MOV DX,0080H ;指定磁头和驱动器号
XXXX:010C INT 13H ;读磁盘操作
XXXX:010E INT 3-d800 ;显示读出内容
二、扇区结构
硬盘主引导扇区占据一个扇区,共512(200H)个字节,具体结构如下:
1.硬盘主引导程序,位于该扇区的0-1BDH处;
2.硬盘分区表,位于1BEH-1FDH处,每个分区表占用16个字节,共4个分区表,16个字节各字节意义如下:
0:自举标志,80H为可引导分区,00为不可引导分区;
1~3:本分区在硬盘上的开始物理地址;
4:分区类型,其中1表示为12位FAT表的基本DOS分区;4为16位FAT表的基本DOS分区;5为扩展DOS 分区;6为大于32M的DOS分区;其它为非DOS分区。
5~7:本分区的结束地址;
8~11:该分区之前的扇区数,即此分区第一扇区的绝对扇区号;
12~15:该分区占用的总扇区数。
3.引导扇区的有效标志,位于1FEH-1FFH处,固定值为AA55H。
三、硬盘主引导扇区的作用
硬盘主引导扇区在各个DOS版本下其内容基本一致,主要完成的任务是:
1.存放硬盘分区表,这是硬盘正确读写的关键数据。
2.检查硬盘分区的正确性,要求只能且必须存在一个活动分区。
3.确定活动分区号,并读出相应操作系统的引导记录。
4.检查操作系统引导记录的正确性, DOS引导扇区末尾也存在着一个AA55H标志,供引导程序识别。
5.释放引导权给相应的操作系统。例如,当确认DOS 操作系统引导记录存在时, 则调出DOS引导程序并执行。
另外,当它发现引导故障时将给出部分提示信息,如:
?Invalid partition table?表示硬盘分区表错误, 没有或存在两个以上活动分区;
?Error loading operating system?表示读DOS引导记录时出错;
?Missing operating system?表示 DOS引导记录无有效标志AA55H。
四、硬盘主引导扇区的应用
正是硬盘主引导扇区直接决定硬盘的安全性, [...]
高级语言反汇编程序的函数调用过程
摘要:本文说明高级语言编译成汇编语言后,高级语言中函数调用的汇编程序过程。
正文:高级语言编译成汇编程序以后,在高级语言中的函数调用的汇编程序过程如下:
1.将函数参数入栈,第一个参数在栈顶,最后一个参数在栈底。
2.执行CALL指令,调用该函数,进入该函数代码空间。
a.执行CALL指令,将CALL指令下一行代码的地址入栈。
b.进入函数代码空间后,将基址指针EBP入栈,然后让基址指针EBP指向当前堆栈栈顶,并使用它访问存在堆栈中的函数输入参数及堆栈中的其他数据。
c.堆栈指针ESP减少一个值,如44H,向上移动一个距离,留出一个空间给该函数作为临时存储区。
{
// 以上准备工作做好后,函数正式被执行,如下所示。
d.将其他指针或寄存器中的值入栈,以便在函数中使用这些寄存器。
e.执行代码。
f.执行return()返回执行结果,将要返回的值存入EAX中。
g.步骤2.d中的指针出栈。
}
h.将EBP的值传给堆栈指针ESP,使ESP复原为2.c之前的值。此时进入函数时EBP的值在栈顶。
i.基址指针EBP出栈,复原为2.b之前的EBP的值。
j.执行RET指令,“调用函数”的地址出栈,本函数返回到CALL指令的下一行。
3.函数返回到CALL指令下一行,将堆栈指针加一个数值,以使堆栈指针恢复到以上步骤1执行之前的值。该数值是上面第一步入栈参数的总长度。
注意:
1.堆栈指针ESP指向栈顶的新入栈数据的最低位。
2.MOV指令中偏移指针指向被“MOV”的数据的最低位。如下面指令是将ebp+8到ebp+11四个字节的内容传到eax寄存器中。
00402048 mov eax,dword ptr [ebp+8]
一个例子如下:
高级语言代码中的函数调用如下:
117: bR = t1(p);
汇编代码如下:
00401FB8 mov ecx,dword ptr [ebp-8] ;将参数放入ecx寄存器
00401FBB push ecx ;参数入栈
00401FBC call @ILT+10(t1) (0040100f) ;函数调用,下一行地址00401FC1入栈
00401FC1 add esp,4 ;函数返回,堆栈指针加4,复原为00401FB8时的值
00401FC4 mov dword ptr [ebp-10h],eax ;从eax中取出高级语言中的函数返回值,放入bR变量中
其中t1函数如下:
125: BOOL t1(void* p)
126: {
00402030 push ebp ;ebp入栈
00402031 mov ebp,esp ;ebp指向此时堆栈的栈顶
00402033 sub esp,44h ;esp减少一个值,空出一段存储区
00402036 push ebx ;将三个寄存器的值入栈,以便在函数中使用它
00402037 push esi ;
00402038 push edi ;
00402039 lea edi,[ebp-44h] ;
0040203C mov ecx,11h ;
00402041 mov eax,0CCCCCCCCh ;
00402046 rep stos dword ptr [edi] ;
127: int* q = (int*)p; ;
00402048 mov eax,dword ptr [ebp+8] ;ebp+8指向函数输入参数的最低位地址;
;如果是ebp+4则指向函数返回地址00401FC1的最低位,值为C1
0040204B mov dword ptr [ebp-4],eax ;
128: return 0; ;
0040204E xor eax,eax ;返回值放入eax寄存器中
129: }
00402050 pop edi ;三个寄存器出栈
00402051 pop esi ;
00402052 pop ebx ;
00402053 mov esp,ebp ;esp复原
00402055 pop ebp ;ebp出栈,它的值也复原了
00402056 ret ;返回到此时栈顶存储的代码地址:00401FC1
;故而如果不幸被修改了返回地址,程序就会出现意外
以上汇编代码由VC++6.0编译得到。
堆栈在EBP入栈后的情况:
低位 高位
↓ ↓
内存地址 堆栈
┆ ┆
0012F600├──────┤← edi = 0012F600
│ │
0012F604├─┄┄┄┄─┤
│ │
│ │
┆ 44h的空间 ┆
┆ ┆
│ │
│ │
0012F640├─┄┄┄┄─┤
│ │
0012F644├──────┤← ebp被赋值后指向该单元,此时ebp=0012F644
│AC F6 12 00 │ebp赋值为esp之前的值
0012F648├──────┤
│C1 1F 40 00 │返回地址
0012F64C├──────┤← ebp + 8
│A0 F6 12 00 │函数实参p的值
0012F650├──────┤
│ │
├──────┤
┆ ┆
注:存储器存储空间堆栈按从高到低的排列,左边标注的地址是其右下方存储单元的最低位地址。如0012F644指向0012F6AC的AC字节,AC在栈顶。图中存储器中的内容按从低到高位书写,“AC F6 12 00”= 0×0012F6AC
MASM-两个16位二进制数减法模拟
功能说明:输入两组16位二进制代码模拟两为16位二进制整数,对其求差并以16进制输出.
基本算法:采用补码,模拟二机制减法(加法类同),得到差(补码)转换成原码后,转化成十六进制并输出.16为二进制转换成4为十六进制数的方法是采用:将16位二进制分成4组,每组由连续4位二进制组成,模拟4位二进制到一位十六进制转换,将每组转换成16进制数并输出.详见代码
本代码在MASM.5调试通过
运行界面:
如
binary(YuanMa) num1=1000000000001011 ;被减数原码
binary(YuanMa) num2=1000000000001101 ;减数原码
binary(Buma) num1 BM=1111111111110101 ;被减数补码
binary(Buma) num2 BM=1111111111110011 ;减数补码
binary(Buma) diff sub=0000000000000010 ;差补码
binary(YuanMa)diffsub=0000000000000010 ;差原码
hex sumHEX=0002
;/************************************************/
;
;bsub.asm
;hbyufan@163.com
;
TSOUT MACRO dx0
mov ah,09h
mov dx,offset dx0
int 21h
ENDM
data segment
num1 db 19 dup(”$”)
num2 db 19 dup(”$”)
sum db 19 dup(”$”)
hexsum db 5 dup(”$”)
tsnum1 db 0ah,0dh,”binary(YuanMa) num1=$”
tsnum2 db 0ah,0dh,”binary(YuanMa) num2=$”
tssum db 0ah,0dh,”binary(Buma) diff sub=$”
tsnum11 db 0ah,0dh,”binary(Buma) num1 BM=$”
tsnum22 db 0ah,0dh,”binary(Buma) num2 BM=$”
tssum33 db 0ah,0dh,”binary(YuanMa)diffsub=$”
tssumhex db 0ah,0dh,”hex sumHEX=$”
data ends
code segment
assume ds:data,cs:code
start:
mov ax,data
mov ds,ax
re:
TSOUT tsnum1
mov si,0
n1roat:
mov ah,01h
int 21h
cmp al,”0” ;对NUM1输入错误简单处理—重新输入
jl re
cmp al,”1”
ja re
mov [...]