重要知识
- 汇编读写
;WriteString ReadString
;WriteString
; Writes a null-terminated string to standard
; output. Input parameter: EDX points to the string.
;ReadString
; Reads a string of up to 128 characters from the console
; past the end of line, and places the characters in a buffer.
; Strips off CR/LF from the input buffer.
; Receives: EDX points to the input buffer,
; ECX contains the maximum string length
; Returns: EAX = size of the input string.
;WriteInt ReadInt
;WriteInt
;Receives: EAX = the integer 输出eax
;ReadInt
;Returns: If CF=0, the integer is valid, and EAX = binary value.
;If CF=1, the integer is invalid and EAX = 0.
;WriteHex ReadHex
;WriteHex
; Writes an unsigned 32-bit hexadecimal number to standard output.
; Input parameters: EAX = the number to write.
;ReadHex
;Reads a 32-bit hexadecimal integer from standard input
;Returns: EAX = binary integer value
;Crlf
; Writes a carriage return / linefeed(写入回车或换行符)
;WriteChar
; Write a character to standard output
; Recevies: AL = character
- 变量的分类(汇编中用大小区分变量)
;DB / byte 定义字节. 8位(一个字节数据占一个字节单元,读完一个,偏移量加1)
;DW / word 定义Word.通常在x86 32位系统上为2个字节(一个字节数据占2个字节单元,读完一个,偏移量加2)
;DD / Dword 定义双字.典型的x86 32位系统通常为4个字节(一个双字节数据占4个字节单元,读完一个,偏移量加4)
- 跳转指令
; jmp :无条件转移指令
; jnc :表示不进位时跳转
; jnz :表示非0跳转
;有符号数比较
; jg :greater than
; jz :zero equal to
; jl :less than
;无符号比较
;ja :above var1>var2
;jz,je var1=var2
;jb :below var1<var2
;xchg 交换两个变量的值
;交换指令XCHG是两个寄存器,寄存器和内存变量之间内容的交换指令,两个操作数的数据类型要相同,可以是一个字节,也可以是一个字,也可以是双字
- 操作数与四则运算
opcode oprand1 [,operand2]
;1.oprand1称为目的操作数
; oprand2称为原操作数
;2.目的操作数不能为常数
;3.两个操作数的类型必须一样(大小相同)
;4.指令如果涉及到两个操作数,两个操作数不能都是内存变量,必须有一个是寄存器
;四则运算
add oprand1,operand2 eflag;无进位
addc oprand1,operand2 CF;有进位
add byte ptr [m1],20;将m1当作byte长度看待
add word ptr [m1],20;将m1当作word长度看待
add dword ptr [m1],20;将m1当作dword长度看待
sub oprand1,oprand2 eflag
mul oprand1 ;结果必须由64位保存,结果储存在edx,eax中(高位在edx中,低位在eax中)
;字节操作数 (AX)
;字操作数 (DX,AX)
;双字操作数 (EDX,EAX)
;mul通过操作数来辨别乘法进行的位数(如果是立即数无法辨别大小)
imul oprand1 ;有进位,存在edx,eax
;被乘数和积在edx,eax组成的64位中
div oprand ;被除数在edx,eax组成的64位中
;结果:商在eax中,余数在edx中(如果被除数是32位记得将edx赋值为0)
- 函数实现
F1 PROC
ret
F1 ENDP
;规定函数返回值放在寄存器内
;函数内用栈保存寄存器信息
isPrime PROC
push ebx
push edx
push esp
pop esp
pop edx
pop ebx
ret
isPrime ENDP
;习惯规定如果返回值32位放的下的话默认放在eax中
- 寄存器的使用
;32位寄存器高16位无法直接使用,对应的低16位AX,BX,CX,DX,SI,DI,BP,SP可视情况使用
;以上16位寄存器还可以细分:
;AX:AH AL
;BX:BH BL
;CX:CH CL
;DX:DH DL
;EAX是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。
;EBX是"基地址"(base)寄存器, 在内存寻址时存放基地址。
;ECX是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。
;EDX则总是被用来放整数除法产生的余数。
;ESI/EDI分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串
;EBP是"基址指针"(BASE POINTER), 它最经常被用作高级语言函数调用的"框架指针"(frame pointer).
;ESP专门用作堆栈指针,被形象地称为栈顶指针,堆栈的顶部是地址小的区域,压入堆栈的数据越多,ESP也就越来越小。在32位平台上,ESP每次减少4字节
;EIP储存下一条cpu执行的指令地址
;EFLAG取值含义
;IP: EI/DI 中断标志位
;中断控制在硬件中完成(接口和CPU中的中断控制指令集)
- X进制常数表示
;进制前缀:
;二进制 0B 0B101010
;八进制 0O 0O767676
;十六进制 0x 0xA7B2
;进制后缀:
;二进制 B
;八进制 O
;十进制 D
;十六进制 H
- 寻址方式
;立即寻址(目的操作数是常量)
;直接寻址(数据在变量内 eg. val)
;寄存器寻址(数据在寄存器内)
;寄存器间接寻址 (不能出现[100],应该用变量定义,再使用变量名;寻址寄存器用32位)
mov eax,offset val
mov ebx,[eax]
;寄存器相对寻址(在寄存器间接寻址的基础上对地址加减偏移量)
;基址—变址寻址
;基址—变址相对寻址
- 指令
;逻辑运算指令
;逻辑非指令 NOT OPR
;逻辑与指令 AND DST,SRC
;逻辑或指令 OR DST,SRC
;异或指令 XOR DST,SRC
;测试指令 TEST OPR1,OPR2
;移位指令
;逻辑左移 SHL OPR,CNT (SHL = Shift Left)
;逻辑右移 SHR OPR,CNT (SHR = Shift Right)
;CNT(存在CL 八位寄存器中)
;串处理指令
;B:BYTE W:WORD D:DOUBLE WORD
;MOVS(MOVSB,MOVSW,MOVSD)
;源串地址放在ESI中,源串长度放在ECX中(以单位偏移量为单位长度),目的串地址放在EDI中
;DF标志位 DF=0时表示ESI/EDI储存串的首地址,DF=1时表示ESI/EDI储存串的尾地址
;STOS 初始化串
;指令对应寄存器(存放初始化单元)
;STOSB AL
;STOSW AX
;STOSD EAX
;LODS 从串地址中取出一个子节/字/双字放在AL/AX/EAX中
;CMPS 比较两个串的大小(较小串长度放在ECX中)
;SCAS 扫描字符串,在字符串中找与AL/AX/EAX中数据相同或不同的子串(比较最大次数放在ECX中)
;设置方向标志位 CTD STD
;CLD指令功能:(STD功能相反)
;将标志寄存器Flag的方向标志位DF清零。
;在字串操作中使变址寄存器SI或DI的地址指针自动增加,字串处理由前往后。
;串重复前缀
;REP REPE/REPZ REPNE/REPNZ
;堆栈操作
;进栈指令
;push pushad
;pop popad
;pushad/popad 可以将寄存器在一行内一次性入栈/出栈
;PUSHAD指令压入32位寄存器,其入栈顺序是:EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI(执行后ESP- 32)
;POPAD指令按照与上面相反的顺序依次弹出寄存器的值,顺序为EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX(执行后ESP+32)
ret
;ret指令的内部操作是:栈顶字单元出栈,其值赋给IP寄存器。即实现了一个程序的转移,将栈顶字单元保存的偏移地址作为下一条指令的偏移地址。
;函数执行完时 ret 12
;栈顶pop 赋值给EIP ESP地址加12
- 小知识点
;分号之后的部分为注释
call DumpRegs ;显示寄存器信息D
;伪指令有2个特点:
;(1)由于是伪“指令”,因而它只存在于汇编语言中。高级语言中不叫指令,叫语句;
;(2)由于是“伪”指令,也即“假”指令,因而不是可执行指令,不会产生机器代码,不会占用ROM空间,只用于汇编过程中为汇编程序提供汇编信息。
mov ebx,var1
cmp ebx,var2 ;var1-var2=>eflag 相减后会改变eflag,执行该语句后var1,var2不变
;负数用的是补码表示方式
;小端编址方式: 00404000 -> 18 FC FF FF
;数组用法:
;arr dd 10 DUP(?)
;arr dd 1,2,34,3,5,6,8 直接为数组赋值
;arrlen = ($-arr) / 4 可以用这种方式动态获得数组大小(注意必须紧连着arr的定义,4代表的是偏移量)
;一个内存地址对应一个字节(Byte): 0xFF 或者说 8-bit:11110000b。
;Excellent db 'Excellent',0 ;''中的字符串不含结束字符0,需要手动添加
lea edx,msg ;==mov edx,offset msg
;lea = load effective address
inc eax ;自增
dec eax ;自减
;操作数可以是变量,不影响CF标志
again:
add v,1 ;inc v 使用inc不会导致eflag改变,inc不会造成进位
jnc again ;jnc 表示不进位时跳转
;相同的mov指令但是选用的寄存器不同机器码也可能不一样
;外设相对于cpu可以看作寄存器
;带符号扩展
;MOVSX reg1, reg2
;MOVSX reg, mem
;如果拓展不用用到高位,高位自动清零
;目的操作数的位数要比源操作数大
;源操作数可以是8位或者16位,而目的操作数必须是16位或者32位
;循环
mov ecx,n ;n为常数
Addr:
;循环体
loop Addr ;ecx-- 并判断ecx与0是否相等,如果不相等,继续循环;如果相等,跳出循环
汇编程序模板
-
模板
TITLE Program Template ;Template.asm INCLUDE Irvine32.inc .data ;此处定义全局变量 .code ;代码段 main PROC exit main ENDP F1 PROC ret F1 ENDP END main
;传参模板(保护现场) push x push y f1 proc push ebp mov ebp,esp sub esp,4 pushad popad mov eax,[ebp-4] add esp,4 pop ebp ret 8 f1 endp ;用栈保存寄存器状态,防止修改寄存器值影响main函数执行
-
基础计算
TITLE Add and Subtract INCLUDE Irvine32.inc .data val1 DWORD 10000h ; h代表16进制,10000h是十进制2^16 val2 DWORD 40000h val3 DWORD 20000h ;finalVal DWORD .data? ;其中的数据段也可以定义在.data中 finalVal DWORD ? ;定义未初始化数据 temp DWORD 2 DUP(?) ;dup在汇编中是一条伪指令,用来重复初始化数据 此处就是将两个DWORD的空间都定为? .code main PROC mov eax,val1 add eax,val2 sub eax,val3 mov finalVal,eax ;将寄存器eax中保存的运算结果保存在数据段finalVal中 call DumpRegs ;显示寄存器信息(registers是寄存器的意思) exit main ENDP END main
-
整数输入输出与比较
INCLUDE Irvine32.inc .data var1 dd ? var2 dd ? ;dd是指doubleword (4个子节) .code main PROC call ReadInt ;读入Interger,存入eax mov var1,eax call ReadInt mov var2,eax cmp var1,eax ;比较var1和eax的大小 jl L1 ;跳转到L1 mov eax,var1 L1: call WriteInt ;输出eax中存放的数 exit main ENDP END main
-
条件判断与分支
INCLUDE Irvine32.inc .data mark DD ? Excellent db 'Excellent',0 ;''中的字符串不含结束字符0,需要手动添加 Good db 'Good',0 Pass db 'Pass',0 Failed db 'Failed',0 .code main PROC call ReadInt mov mark,eax cmp eax,90 Jb L1 mov edx,offset Excellent jmp final L1: cmp eax,80 jb L2 mov edx,offset Good jmp final L2: cmp eax,60 jb L3 mov edx,offset Pass jmp final L3: mov edx,offset Failed final: call WriteString ;WriteString的使用与EDX有关 exit main ENDP END main
-
输入10个整数比较大小
INCLUDE Irvine32.inc .data arr dd 10 dup(?) .code main PROC mov ebx,0 again1: cmp ebx,10 jae final1 call ReadInt mov [arr + 4*ebx],eax add ebx,1 jmp again1 final1: mov ebx,1 mov eax,[arr] again2: cmp ebx,10 jae final2 cmp eax,[arr + 4*ebx] jae L1 mov eax,[arr + 4*ebx] L1: add ebx,1 jmp again2 final2: call WriteInt exit main ENDP END main
-
判断32位以内自然数是否为素数
INCLUDE Irvine32.inc ;正整数判断是否是素数 .data val1 dd ? val2 dd 2 YES db 'Yes',0 NO db 'No',0 .code main PROC call ReadInt cmp eax,1 jz result1 mov val1,eax mov edx,0 div val2 mov ecx,eax mov edx,0 again: mov edx,0 mov eax,val1 cmp ecx,1 jz result2 div ecx cmp edx,0 jz result1 ;sub ecx,1 loop again result1: mov edx,offset NO call WriteString jmp over result2: mov edx,offset YES call WriteString over: exit main ENDP END main
-
输入整数输出不带加号整数
INCLUDE Irvine32.inc .data val1 dd ? val2 dd 10 msg db '0',0 .code main PROC call ReadInt mov val1,eax mov ecx,0 again: mov edx,0 mov eax,val1 div val2 mov val1,eax mov eax,edx add al,'0' push eax add ecx,1 mov ebx,val1 cmp ebx,0 jz over jmp again over: again1: pop eax call WriteChar loop again1 exit main ENDP END main
-
ret使用案例
INCLUDE Irvine32.inc .data msg1 db 'Hello world',0 msg2 db 'Goodbye',0 .code main PROC push next jmp f1 next: call crlf lea edx,msg2 call writeString exit main ENDP f1 PROC lea edx,msg1 call writeString ret f1 ENDP END main
-
进制转换
INCLUDE Irvine32.inc .data val1 dd ? val2 dd ? arr db '0123456789ABCDEF' .code main PROC call ReadInt mov val1,eax call ReadInt mov val2,eax call change exit main ENDP change PROC mov ecx,0 again: mov edx,0 mov eax,val1 div val2 mov val1,eax mov al,[arr+edx] push eax add ecx,1 mov ebx,val1 cmp ebx,0 jz over jmp again over: again1: pop eax call WriteChar loop again1 ret change ENDP END main
-
选择排序(升序)
INCLUDE Irvine32.inc .data arr dd 1,100,-9,-8,-100,2000,435,875,-2321,0 arrLen = ($ - arr) / 4 tempLen dd arrLen msg1 db "Before sort : ",0 msg2 db "After sort : ",0 .code main PROC mov edx,offset msg1 call WriteString call crlf mov esi,0 again1: cmp esi,arrLen jz next1 mov eax,arr[4*esi] call WriteInt mov al,' ' call WriteChar inc esi jmp again1 next1: call crlf mov esi,1 mov ecx,tempLen again2: cmp esi,arrLen jz next2 call findMaxIndex dec ecx ;call WriteInt ;call crlf mov ebx,[arr+4*ecx] mov edx,[arr+4*eax] mov [arr+4*ecx],edx mov [arr+4*eax],ebx ;mov eax,ecx ;call WriteInt ;call crlf inc esi jmp again2 next2: mov edx,offset msg2 call WriteString call crlf mov esi,0 again3: cmp esi,arrLen jz next3 mov eax,arr[4*esi] call WriteInt mov al,' ' call WriteChar inc esi jmp again3 next3: exit main ENDP findMaxIndex PROC push esi mov esi,0 mov eax,0 again: inc esi cmp esi,ecx jz over mov ebx,[arr+4*eax] cmp ebx,[arr+4*esi] jge next mov eax,esi next: jmp again over: pop esi ret findMaxIndex ENDP END main
-
求最大公约数
INCLUDE Irvine32.inc .data m dd ? n dd ? r dd ? msg db '最大公约数是:',0 .code main PROC call ReadInt mov m,eax call ReadInt mov n,eax cmp m,eax ;保证 m >= n jge next xchg m,eax xchg n,eax next: call gcd mov eax,m mov edx,offset msg call WriteString call WriteInt exit main ENDP gcd PROC again: mov edx,0 mov eax,m mov ebx,n div ebx mov m,ebx mov n,edx cmp edx,0 jz next1 jmp again next1: ret gcd ENDP END main
-
求完美数
INCLUDE Irvine32.inc .data k dd ? count dd 0 .code main PROC call ReadInt mov k,eax mov esi,0 mov ebx,2 again: cmp esi,k jz next call findNum mov esi,count inc ebx jmp again next: exit main ENDP findNum PROC push eax push esi mov esi,1 mov ecx,0 again1: cmp esi,ebx jz over mov eax,ebx mov edx,0 div esi cmp edx,0 jnz next1 add ecx,esi next1: inc esi jmp again1 over: cmp ecx,ebx jnz next2 mov eax,ebx call WriteInt call crlf inc count next2: s pop esi pop eax ret findNum ENDP END main
-
正整数的素数分解
INCLUDE Irvine32.inc .data n dd ? temp dd ? divNum dd 10 .code main PROC call ReadInt mov temp,eax mov n,eax mov ecx,0 again3: cmp eax,0 jz next4 mov edx,0 div divNum push edx inc ecx jmp again3 next4: again4: cmp ecx,0 jz next5 pop eax add al,'0' call WriteChar dec ecx jmp again4 next5: mov al,'=' call WriteChar mov esi,2 again: mov ecx,0 call findPrime cmp ecx,0 jz next2 mov eax,esi add al,'0' call WriteChar mov al,'^' call WriteChar mov eax,ecx add al,'0' call Writechar mov eax,temp cmp eax,1 jz next3 mov al,'*' call WriteChar next3: next2: cmp esi,n jz next inc esi jmp again next: exit main ENDP findPrime PROC again1: mov edx,0 mov eax,temp div esi cmp edx,0 jnz next1 inc ecx mov temp,eax jmp again1 next1: ret findPrime ENDP END main
-
byte ptr [arr]测试
INCLUDE Irvine32.inc .data arr1 dd 1,5,3,6,234,2,56 arr2 db 123,4,44,111,67,34,7,88 arr3 dw 113,3455,67,234,777,432,1,3,5 .code main proc mov eax,dword ptr [arr1] ;使用时源操作数和目的操作数类型需要对等 call WriteInt mov al,byte ptr [arr1] call WriteInt mov ax,word ptr [arr1] call WriteInt exit main endp end main