汇编语言速成

1、配置环境

资料:http://t.csdnimg.cn/mnbxA

http://t.csdnimg.cn/9o6lx

补充:stc ah,10H:给ah赋10(16进制),并把进位标志cf设置为1

下载:GitHub

使用参考:vscode进行汇编编程,你想要的都有_哔哩哔哩_bilibili 

建议在浏览器扩展商店搜索GitHub加速插件并安装 

点击下面绿色链接

c82e6baf33b94bf7ac6b9cb0a3f549f0.png复制这些网址到设置页面 34157e2710794b1cb9e390d369c95650.png

86a8641550a2405890d8db9bc5ab8285.png

注:我在按右上角运行符号使用时发现,更改代码后第一次运行无效,第二次运行才是更改后的结果!(也可以ctrl+s保存后运行) 

或者按ctrl+b选择dosbox运行

汇编不区分大小写

f5ffcd2f633f47b682bcae33a29f09d5.png

 点开dosbox后,通过mount指令把工作区挂靠到指定的文件夹下,然后c:进入工作区,dir查看工作区文件

687adbdac01c4947a0c151905260e76c.png

输入masm、ASM文件名开始编译,生成obj文件,如果masm报错就把MASM.EXE复制一个到工作区 

b88b087412f4467e8bb1a9f2f298f3d4.png

连接

7374dc2bc06e4796a420a222169d0ef5.png

输入debug learn.exe执行(说非法依赖就粘贴一个debug.exe过来)

c6ed060b44e5454bb47ceba4d2f6f923.png

2、debug

7102eb8a7d974a84a3a9dd79475c8d48.png

EAX为32位寄存器
AX为EAX的低16位的 “ 子寄存器 ”
——这么叫是为了方便理解 

1bf2a6d4bbe34170acfab7dcdb182d9b.png

巧记:truead,t:execute(执行),r:read,u:Translate,a:add,d:du(读)

在dosbox打dir,查看当前环境下有哪些文件

再打debug进入debug,此时可运行debug指令,输入q可以退出debug

r:查看各寄存器的值

r ax:修改AX的值

4f69a9f7f7914969b164f9b44196db4c.png d 1000:0 :查看段地址1000处的内存

d:使地址不断偏移

d 1000:0000 f :限制输出15个 ,后面的数字可任意更改

451e53594c69420cbbe1ea57bb7f45bc.png

d 1000:9:从9位置开始输出(即偏移地址为9)

 e 1000:0010 12 23 34:修改0010上数据

e 1000:0010回车出现第一个,写上值,空格出现第二个,写值,然后回车,完成修改:

54f62592fb954cd48d771d496bf3e89f.png

选择cs寄存器写程序: a 0740:0100,回车,add ax,bx(把ax+bx的结果放进bx),回车,mov cx,ax(把ax拷一份放到cx)

t:执行一步程序,0740:0104即CS:IP

g 0012:执行到ip=0012

p:遇到loop循环时,直接执行完这个循环

25d79c602a8a48d0b4b518e5da35267c.png

d CS:原IP(这里是0740:0100): 查看机器码(机器码在内存中样子)

u CS:原IP(这里是0740:0100):把机器码翻译成汇编代码,这里显示的是之前写入的指令

5d2e84d37c254df98fecace414ee6b3e.png

3、MOV、ADD、SUB(只能操作ax,bx,cx,dx寄存器)

mov ax,8:给ax赋值8 (把8移入ax) 

mov bx,ax:给bx赋ax的值(自己赋值给自己也可以)

mov ch,10:给cx的高位(cx由两个十六进制数拼成)赋值10,得到1000

mov dl,12:给dx的低位赋值12(t执行完后直接a回车可以再写汇编代码)

mov cl,al:给cx的低位赋值ax的低位

c9b6dbddaa344f8182b98b218e7060c9.png

2ee3389c26b54f5fa72185222cada653.png18fe2a24b6884b16ad5c9abf198bc64a.png add ax,15:给ax加上15

add cx,bx:给cx加上ax的值(自己加自己也能用,如果加越界了会把超出的高位忽略)

add bh,f0:给bx高位加上f0(给低位加超限了也不会向高位进位)

add dh,bh:给dx的高位加上bx的高位

d433524a3f10460296bd04ed48db3b2f.png

107478460a9f44f394244bf938f002f9.png sub ax,d:给ax减去d(如果减越界了,会把ax补成1001d再减d,如果低位减越界了,也不会向高位借位)

sub ax,bx:给ax减去bx的值,结果存在ax

1881ccc91b88492d88c51477fd512983.png

4、mul、div、and、or 、xor、neg、not

8dd75b572ebe44a2acd68651eefa6190.png

mul bl:将al与bl相乘,结果存在ax中(ax中存的下,不会溢出)

mul bx:将ax与bx相乘,结果高位存在dx,低位存在ax(同理,不会溢出)

4b62874c71b04db3be16254354b37569.png

0c008280b5f746d49b311a6c4ccda16b.png div bl:拿ax除bl,商存在al中,余数存ah中

div bx:拿dxax除bx,ax存商,dx存余数

7e75e7d45d0c42c4a6b64ca1e0b24cd8.png

8c2d4e08c8ad491bb62ca2e5c91c92d0.png

271b7eef13e24f2081fad01f25b1b3e8.png

and al,3b:取63和3b的逻辑与(同为1才1),存在al中

想保留16进制最后一位,就与上000f,前三位与0与全0,最后一位全和1与不变

01f47f95437448ee88fbad314664a7b0.png521b90c119b54ba8b6aec5e733d41d7e.png 

 and al,3b:取63和3b的逻辑或(有1就为1),存在al中

12a2cefdb7cd4b77a7884cfccaec1809.png

xor al,dh:按位二进制异或(先写出二进制,再每位异或) 

NEG:把操作数按位取反加一 (可以用来求一个数的相反数)

NOT:把操作数按位取反

遇到0f0f0H取f0f0

5、shl、shr 

切记al是8位,移位的时候不要分成两个四位分别移!!!

shl ax,1:普通左移,移一位,在右边补0

shr ax,1:普通右移,在最左边补0

sal:将数视为有符号数进行左移,不挪走符号位(首位),后面补0

sar:将数视为有符号数右移,不挪走符号位,负数补1,正数补0(补符号位的数)

rol ax,1:循环左移:把最左边的数移到最右边

ror ax,1:循环右移

rcl:把原来CF的值移入最低位,在把最高位的值移出给CF

RCR ah,1:这时候CF很重要,先把原来CF的值移入最高位,在把最低位的值移出给CF

RCL:带进位循环左移,先将CF的值给最低位,然后最高位的值在进CF

inc ax:使ax加1(越界按加法抹头)

dec ax:使ax减1 (越界按减法借位)

nop:空指令,执行后什么都不变,用来占位,刚好占一个字节

xchg ax,bx:交换ax,bx的值

neg ax:给ax取反(取-ax的补码) 

int 0:中断指令,不同错误会产生不同值,后会跳到0000:0000的对应值的位置

算10ax=8ax+2ax:

7bf9ed4c8cf642d891fcf9b758364c2c.png

60d49f7e22164c6daba5a4f2a1d2c5f2.png

6、段地址、偏移地址 

2000:1f60和2100:0f60是同一个物理地址

2b438869db0540f9b616072104dce81a.png

ds寄存器存的是段地址,给它赋值

mov bl,[61]:把21f0:0061处的值赋值给bl

add bl,[60]:21f0:0060处的值加给bl

mov bx,[62]:0062处的值赋值给bl,0063处的值赋值给bh(mov ax,[bx+1]、mov [bx+1],ax也可以,只有bx、si、di、bp(默认使用ss:bp为地址,要改ss)、bx(bp也可以)+si+1、bx+di+1可以这样当偏移地址用)

9949eb9e60494544bc3b5ebd8c5b08f0.png cs、ip是代码段寄存器,cs存的是段地址,ip存的是偏移地址,es也可以存段地址

ds是数据段寄存器

在某个地址写好代码后,要给cs、ip赋值再输入t执行

输入t执行后,ip会自动加一定数,移到下一句代码处

jmp 1000:3:跳转到1000:0003处,cs改成1000,ip改成0003

jmp bx:跳转到ip=bx处

汇编代码和数据不加区分,可以到处赋值

404cd843496147e181b8489d1e8d497f.png8cb6c9df203b4a778029dd384bccab2b.png

d2312d7b965e4e1fbff01c0778574a6a.png 下面的写法都是表示把各元素相加

f51ecdd7eca04992b4c73b23eb19455a.png

7、栈 

ss:sp指向栈顶元素,压栈sp-2,弹栈sp+2,栈弹完了继续弹,sp正常+2,因为读到0的数据,会赋值0,要自己小心

mov ss,ax

mov sp,2设置栈顶

push ax:把ax压入栈

push [0]:把ds:0000处数据压栈

pop ax:把栈顶元素弹出,并赋值给ax 

pop [1]:把栈顶元素弹出,并赋值给ds:0001

e0126d9a44ea4ec6a06bdf69589b806a.png

8、标志位寄存器 

bdb42fcedde84e83a33a4ef2078efcb6.png

zf:如果执行指令后结果为0,zf=1(显示ZR),否则zf=0 (显示NZ)

cmp ax,bx:运算为ax-bx,但是不保存结果,通过看zf可以判断两者是否相等(zf=1,相等)

ax<bx:cf=1 ,ax>bx:cf=0,zf=0 ,ax>=bx:cf=0 , ax<=bx:cf=1或zf=1

下面的跳转指令可以跳到正在执行的代码中任意一条代码的地址 

b7da87681f0245eda6ea1b41105bc5af.png

feea6108333c479ea5de024f104f0f0d.png

pf:执行指令后如果1的个数为偶数,pf=1(显示PE),否则pf=0 (显示PO)

sf:执行指令后为负数,sf=1(显示NG),否则sf=0 (显示PL) 

cf:执行指令后如果需要进位(比如shl把1移没了)或者借位(无符号数),cf=1(显示CY),否则cf=0(显示NC) 

adc ax,1:带进位加法指令,结果是ax+1+cf

sbb ax,bx:带借位减法,结果是ax-bx-cf 

of:执行指令后,以无符号数首位为符号位的有符号数如果溢出(比如符号是1,左移移没了),of=1(显示OV),否则of=0(显示NV) 

TEST指令:一种用于逻辑运算的指令。它可以对两个操作数进行逻辑AND运算,并根据运算结果设置标志位。

stc:把cf的值置1 (setcf),同理有clc置0

std:把df置1

cld:把df置0 (cleardf,这里的0可能表示二进制正号,表示正向移动)

df标志位用于数据串操作,即通过MOVS/MOVSB(db写的字节数组专用)/MOVSW(dw写的字数组专用)把段地址在DS中,数组地址在SI中的串中的字符拷贝到段地址在ES中,数组地址在DI中的串(一般前面的两个数组都在数据段data,可以MOV AX,data,再mov ds,ax、mov es,ax),其中df=0在执行MOVSB等指令后使SI、DI加一(要拷贝整个数组,则SI、DI从首位开始,一个个加到末位),df=1使SI、DI减一(要拷贝整个数组,则SI、DI从末位(可以数字符串长度后再减一得到,再加到SI上)开始,一个个减到首位)

如果不想用loop循环控制MOVSB执行,可以在cx中写入需循环次数,再rep movsb循环执行movsb相应次数(拷贝整个数组一般mov cx,sizeof 需拷贝数组名)

MOVSB、MOVSW同理的有以下指令:

lodsb指令,将si指向的地址处的数据取出来赋给AL寄存器,si=si+1;
lodsw指令则取得是一个字:将si指向的地址处的数据取出来赋给AX寄存器,si=si+2
lodsd指令,取得是双字节,即mov eax,[esi],esi=esi+4;

stosb指令,将AL寄存器的值取出来赋给di所指向的地址处。mov [di],AL;di=di+1;
stosw指令去的是一个字。
stosd指令,取得是双字节,mov [di],ax;di=di+4;

jnz、jne这两条指令完全没区别! 它们对应于完全相同的机器代码,含义为ZF标志位不等于0 则执行

jcxz(jump if cx is zero):是短转移,当cx=0就跳转

jge ax,1:ax大于或者等于1转移

JA      ;大于跳转
JAE     ;无符号大于等于则跳转
JB      ;无符号小于则跳转
JNB     ;无符号不小于则跳转
JBE     ;无符号小于等于则跳转
JG      ;有符号数大于则跳转
JL      ;有符号数小于则跳转

JLE      ;有符号数小等于则跳转
JC      ;CF进位则跳转(无符号为进位)
JO      ;OF溢出则跳转(有符号为溢出)

笔试答案可以写二进制如00001000B,如果题目用到了字符也可以写字符(65是A,97是a)

9、源文件写代码

文件中可以mov ax,0010B存二进制,不写默认十进制,写H16进制(不能字母打头),写O8进制

align:用来对齐 

loop指向函数(即图中的s)开始处的ip(那句mov的IP),以cx为计算器,cx!=0时,每次执行到loop都会跳到对应的ip,实现循环,每执行(遇到一次loop)一次loop指令cx-1 (减完为0就退出循环,cx赋值0会死循环!)

小心循环中两个移位语句产生的cf互相影响(不是rcl、rcr不受影响)

142de26057ef4c82a4ac24888ed93797.png

8e3e3b938ca44470815e2ce6b527ed41.png 6aaa2c0e35774e42afcbbf4a6d9295c1.png370edf0983ff4f66b4b05cbf4641707f.png44401f642a4449feb7439dd2f90a15a2.png

汇编函数本质更接近c++的goto 

call(近转移,只把call下一句的IP压入栈)、call far ptr(远转移,同时压栈cs和ip,当call和函数距离太远,cs不同时用)指令调用函数,ret(近转移,只修改IP,即把栈里的数据弹给ip)、retf(远转移,同时修改cs和ip,当call和函数距离太远,cs不同时用)即renturn,标志函数结束,这种写法函数和主程序的代码不会分开存,还是按行数顺序存,这里删了结束语句int 12H会死循环,因为跳过call后继续下面的add,然后又ret回来

如果函数没写ret,会继续执行函数下面的代码直到结束

如果运行到ret时没有call与之对应,会返回程序的第一句,造成死循环

d3253c22aab94da094fa8ab494187077.png

标准文件:

8b7ea8d41b4c4dbebb0c3e9eb3f99af8.png

if、if else翻译成汇编 

e2ebf541e46d4edf9e1d62bc158d334e.png

10、代码段、数据段、栈段

可以mov ax,代码段名(栈段名、数据段名)获取段的段地址 

下面这样写数据,会把数据写到代码段,因为汇编不区分代码和数据,会产生混淆(数据和mov指令存在一起,导致不能识别mov)

dw等写法一写好就存入数据,不用t运行,按顺序放,不看高低位,dw是16位,如果值是8位会补0再存 

存字符串要用db(占一个字节),不能用dw(占一个字)

若遇到编译问题,注意dw等中十六进制尾部加H,不能字母打头,头部加0

用start标记代码开始执行位置,避免混淆(数据仍然存在代码段,和代码存一起且不能正常翻译,但是能正常执行)

1b790676fcc44acf8f66d684af9cd9f5.png 88aab11d584f481f9a737052f665a706.png

分多个段存数据、栈、代码 

e4f5c6ab9b9d4d02985b10c781e2c40a.png db 10 dup(0):存10(十进制)个0

如果没有start:数据在前面,代码在后面,识别从前面开始,读不到代码

e5e5d0675eb44a4d83af720490c89ef3.png

11、offset转移指令 

SI (Source Index):源变址寄存器

DI (Destination Index):目的变址寄存器

offset:获取s的地址

jmp short s、jmp near ptr s:跳转到s函数的第一行代码,只改ip

jmp far ptr s:跳转到s函数的第一行代码,改cs、ip

jmp word ptr ds:[0]:从ds:0000处读4个16进制数作为跳转目标,近转移,远转移是dword

mov word ptr ds:[0],0:把0当0000存入这个地址

lea dx,arr1代替mov dx,offset arr1

下面代码只执行s部分,把mov拷到s0中(mov占2字节) 

263dec8603734d449e7f749fd5c20244.png

12、数组 

数据段中 arr db 12,34定义数组

mov ax,type arr获取arr每个元素占的字节大小(1是byte型(db写的),2是word型(dw))

mov ax,数据段名

mov ds,ax(相当于mov si,offset arr)

mov ax,arr[0](相当于mov ax,ds:[si+0]):获取数据三步(取0可以不写[0]),反过来可以写入数组

代码段中 arr db 12,34定义数组 (注意start应该在它下面写)

 mov si,offset arr:获取数组段地址

mov ax,arr[0]:获取数据(数组是dw写的,0位到1位只移动一个字,而不是一个字节,所以真正的1位在2)

mov ax,word ptr arr[0]: 数组是db写的时,转为16位存入ax(读两个字出来)

byte ptr xxx 从xxx的低位开始,取第一个字节的值
word ptr xxx 从xxx的低位开始,取前2个字节的值
dword ptr xxx 从xxx的低位开始,取前4个字节的值 

二重循环语法:

1744af9bf42c4aea9564acd22f9f3185.png

13、实战代码 

comment*
这是多行注释语法
这个asm文件名叫learn.asm
*comment
ASSUME CS:daima,DS:shuju,ss:zhan;没有指定会报Can't address with currently ASSUMEd segment registers

shuju SEGMENT
    arr DB "你好世界b",10,'下一行',32,'空格','$'
    ;10是换行符,32是空格(即它们对应的十进制ascall码)
    ;'$'是截止符,避免dosbox运行learn.exe文件时出现乱码
    arr1 DB 10,"HeLlo",32,"WoRLd",'$'
    arr2 DB 13 dup(0),'$';用dup开13个空间,填0,注意没有'$'就会把arr3当成arr2的一部分
    arr3 DB 210,223,243,210,222,228,'$'
    arr4 DB 10,13 dup(0),'$'
shuju ENDS

zhan SEGMENT
    DB 100 dup(0)
zhan ENDS

daima SEGMENT
    hanshu:
    MOV AX,shuju
    MOV DS,AX;存入数据段地址
    mov AX,zhan
    mov ss,AX;存入栈段地址
    MOV DX,OFFSET arr;把要显示的地址输给dx
    ;显示字符串
    MOV AH,9;代表显示字符串的ah值
    INT 21H;中断指令,根据ah的值不同执行不同操作

    ;因为大小写变换是ascall码加减20,20的二进制是0100000
    ;任何字母与上1011111变成大写(会破坏空格的32导致不能正常显示后半部分)
    ;任何字母或上0100000 变成小写
    MOV CX,10;定义循环次数
    MOV bx,1;只能用bx处理循环数据,赋值1是为了跳过换行符
    xunhun:
    MOV al,arr1[bx]
    and al,1011111B;与运算
    ;or al,0100000B;或运算
    MOV arr1[bx],al
    a:inc bx;bx++
    cmp arr1[bx],32
    je a;上面相等时goto到a处代码,避免乱改空格
    LOOP xunhun;循环cx次执行goto到xunhun代码
    ;MOV DX,OFFSET arr1;把要显示的地址输给dx
    lea DX,arr1;把要显示的地址输给dx
    ;显示字符串
    MOV AH,9;代表显示字符串的ah值
    INT 21H;中断指令,根据ah的值不同执行不同操作

    ;求arr1每位及以前的最大数,存在arr2中
    MOV arr2[0],10
    MOV bx,1
    MOV cx,12
    MOV AX,0
    MOV ah,0FFH
    xh:
    MOV al,arr1[bx]
    cmp ah,al
    ;jnb xh1;前面最大的大等于现在的,则ah也是现在的最大值
    jna xh1;前面最小的小等于现在的,则ah也是现在的最小值
    MOV ah,al;如果现在的大,给ah赋值完再存
    xh1:
    MOV arr2[bx],ah;最大值存在ah中,把ah存入数组
    inc bx
    loop xh
    lea DX,arr2;把要显示的地址输给dx
    ;显示字符串
    MOV AH,9;代表显示字符串的ah值
    INT 21H;中断指令,根据ah的值不同执行不同操作
    
    ;给数组arr3求和
    MOV cx,6
    MOV bx,0
    MOV AX,0
    xh2:
    add Al,arr3[bx];给ax加八位必须这样写
    ;word ptr读数组会直接读十六位,而不是把八位转16,对寄存器则不能用
    adc ah,0;加的时候带上进位
    inc bx
    loop xh2
    MOV bx,1
    MOV ch,10
    xh3:div ch
    add ah,'0'
    mov arr2[bx],ah
    mov ah,0
    inc bx
    cmp al,0
    jne xh3;商不为0就继续除
    mov arr2[bx],'$';使数字后的其他字符不显示
    mov arr4[bx],'$';把arr2倒着拷到arr4,正常显示数组和
    dec bx
    mov si,bx;只有si、di、bx可以用来当数组下标,用别的报Illegal indexing mode
    mov di,0
    xh4:
    mov cl,arr2[si];两数组元素不能互相赋值,要用寄存器转接一下
    mov arr4[di+1],cl
    dec si
    inc di
    cmp si,0
    ja xh4
    ;用栈反转arr2,正常显示数组和
    mov si,1
    mov cx,bx
    mov dx,0
    for:
    mov dl,arr2[si];因为栈只能操作16位,要把数组元素转成16位入栈
    push dx;只有dw的数组元素可以直接入栈
    inc si
    loop for
    mov si,1
    mov cx,bx
    for1:
    pop Dx
    mov arr2[si],dl
    inc si
    loop for1
    lea DX,arr2;把要显示的地址输给dx
    ;显示字符串
    MOV AH,9;代表显示字符串的ah值
    INT 21H;中断指令,根据ah的值不同执行不同操作
    lea DX,arr4;把要显示的地址输给dx
    ;显示字符串
    MOV AH,9;代表显示字符串的ah值
    INT 21H;中断指令,根据ah的值不同执行不同操作

    ;程序正常退出
    MOV AH,4CH;给ah赋表示退出的值
    INT 21H
daima ENDS;记住代码段和函数的结束语法
END hanshu

67eba783263c43f0b76278a50ecf564b.png

14、补充

 

 

15、笔试题分析 

常用断点功能汇总

输出从ds位置开始的字符串(需要'$'作为终止符,否则不能正常停止输出)

MOV AH,9;代表显示字符串的ah值

INT 21H;中断指令,根据ah的值不同执行不同操作

输出dl中的字符

MOV ah,2H

INT 21H

将读取到的字符串输入dx位置的数组(第一个有效位是arr1[2]

MOV DX,OFFSET arr1[0];把字符串读入arr1

    mov ah,0AH

    INT 21H

将读取到的一个字符输入AL

mov ah,1

    INT 21H

正常退出程序

MOV AX,4C00H

INT 21H

常见思维总结

注意题目要求输出什么、以什么形式输出(会在[]规范输出格式如[1,1]要求输出1,1,要有逗号)

注意求什么不等于输出什么!!

注意题目要求的数据段形式,如果出现  .DATA则表示要求用下面的标准形式写代码 

此写法或许只能mov bx,OFFSET ARRAY 、mov ax,[bx]、add bx,2(word型)访问数组元素?

答案:笔试标准是这种写法,mov ax,ARRAY[bx]可能不给分

.MODEL SMALL

.DATA

  DATA DW 12345

  ARRAY WORD 82,13,13

.CODE

MAIN PROC FAR

MOV AX,@DATA

MoV DS,AX

;代码……

END MAIN

字符0是30H,加上它使数字转字符,字符9是57,如果转字符的结果大等于58,就要再加7转成字母(字母A是65,a是97)

10=0AH是换行符,13=0DH是回车符,输出dl中的字符成为字符串后,要依次输出回车、换行(可以事先放数组里,用时输出数组)再终止程序

任何字母与(AND)上1011111B变成大写(会破坏空格的32导致不能正常显示后半部分)

任何字母或(OR)上0100000B 变成小写

要先判断字母是否在范围内再用

如果要比较绝对值且可能出现负数,要先比较是否小于0,如果小于0,对它取反加1即取补再与其他数比较(NEG指令),注意正常比较不要这样操作!!

数据段运算符

 TYPE运算符返回变量的当个元素的大小,这个大小是以字节为单位计算的。比如,TYPE为字节,返回值位1;TYPE为字,返回值是2;TYPE为双字,返回值为4;TYPE为四字,返回值为8.示例如下:

.data
var1 BYTE ?  ;TYPE=1
var2 WORD ?  ;TYPE=2
var3 DWORD ? ;TYPE=4
var4 QWORD ? ;TYPE=8

LENGTHOF运算符计算数组中元素的个数,元素个数是由数组标号同一行出现的数值来定义的。示例如下:

.data
byte1 BYTE 10,20,30         ;3
array1 WORD 30 dup(?),0,0   ;30+2
array2 WORD 5 dup(3 dup(?)) ;5*3   循环填充5*3次?
array3 DWORD 1,2,3,4        ;4
digitStr BYTE "12345678",0  ;9

myArray BYTE 10,20,30,40,50, 结果是5,即第一行的数字数
             60,70,80,90,100

SIZEOF运算符返回值等于LENGTHOF与TYPE返回值的乘积。如下例所示,intArray数组的TYPE=2,LENGTHOF=32,因此,SIZEOF intArray=64:

.data
intArray WORD 32 DUP(0)
.code
mov eax,SIZEOF intArray ;EAX=64

将二进制数转换成十六进制数

​
​
这个汇编程序的目的是将一个二进制数(数据段中的12345)转换为十六进制数并输出。我们将一步步分析这个程序的操作。

1. 设置数据段:
   ```
   .MODEL SMALL
   .DATA
   DATA DW 12345
   ```

   这里设置了一个名为"DATA"的数据段,其中包含一个双字(2字节)长度的数值12345。

2. 设置代码段和主程序:
   ```
   .CODE
   MAIN PROC FAR
   ```
   这里定义了代码段(CODE)和一个远程过程(PROC FAR)。远程过程允许跨段调用。

3. 初始化数据段寄存器:
   ```
   MOV AX,@DATA
   MOV DS,AX
   ```
   将数据段的地址加载到AX寄存器中,然后将AX的值复制到DS寄存器。DS寄存器用于访问数据段。

4. 加载数据到BX寄存器:
   ```
   MOV BX,DATA
   ```
   将DATA处的二进制数12345加载到BX寄存器中。

5. 设置计数器:
   ```
   MOV CH,4
   ```
   将4存入CH寄存器,这是一个计数器,表示要循环4次,因为十六进制数的每个字符表示4位二进制数。

6. 循环开始:
   ```
   ROTATE:
   ```
   这是一个标签,用作循环开始的地方。

7. 左移数据:
   ```
   MOV CL,4
   ROL BX,CL
   ```
   将4存入CL寄存器,然后将BX寄存器的值左移4位。这是为了得到二进制数的下一个4位数字。

8. 截取低4位并转换为ASCII:
   ```
   MOV AL,BL
   AND AL,0FH
   ADD AL,30H
   ```
   将BL寄存器(存放BX中的低8位)中的值移动到AL寄存器,与0FH(即00001111)执行AND运算以保留低4位。接着,将ASCII码基数30H(即48,表示字符'0')加到AL上,将其转换为ASCII字符。

9. 判断并处理字母A-F:
   ```
   CMP AL,3AH
   JL PRINTF
   ADD AL,7H
   ```
   比较AL是否小于3AH(即58,表示字符':')。如果小于,说明AL已经是一个有效的数字字符,转到PRINTF。否则,加上7H(即7),将其转换为大写字母A-F。

10. 输出字符:
   ```
   PRINTF: 
   MOV DL,AL
   MOV AH,2H
   INT 21H
   ```
   在PRINTF标签处,将AL中的字符移动到DL寄存器。设置AH寄存器为2H,这是DOS的字符输出功能。调用INT 21H,DL中的字符将被显示。

11. 检查是否完成循环:
   ```
   dec ch(原题这里填MOV DL,AL,执行出现死循环)
   JNZ ROTATE
   ```
   检查是否输出了4个字符。如果DL中的值不为零,则跳回ROTATE继续循环。否则,循环结束。

12. 退出程序:
   ```
   MOV AX,4C00H
   INT 21H
   MOV AX,4C0H
   END MIAN
   ```
   设置AH为4CH,表示DOS退出程序功能。然后调用INT 21H。最后,设置AX为4C0H,表示程序正常结束。

此程序将十进制数12345转换为十六进制表示并输出。分析完整汇编代码后,可以看到程序如何一步步完成这个任务。

​

​

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值