汇编语言的学习
<h2>寄存器</h2><p>在DOSBox里面有ax,bx,cx,dx,sp,ip,ds,之类的,如下图</p>
<p><img alt="" height="171" src="https://img-blog.csdnimg.cn/1ac8a81b4e604e8fbd5f356788ec50cb.png" width="1085"></p>
<p> 寄存器的种类</p>
<p></p>
<p>可以分为数据类和指令类</p>
<p>AX(AH、AL):累加器</p>
<p>BX(BH、BL):基址寄存器</p>
<p>CX(CH、CL):计数寄存器</p>
<p>DX(DH、DL):数据寄存器 //不过这些都可以修改,一般就数据和指令。</p>
<h3>指令</h3>
<p>指令的选择是通过cs:ip来选择的。</p>
<p>其中cs代表段地址,ip代表偏移地址</p>
<p>选择该地址内容的数据做为指令。例如:</p>
<p><img alt="" height="545" src="https://img-blog.csdnimg.cn/3aec35b1657445089d78fdb3b55457d8.png" width="1061"></p>
<p></p>
<h3>数据</h3>
<p>数据的选择是通过ds:偏移量来确定的,例如:</p>
<p><img alt="" height="363" src="https://img-blog.csdnimg.cn/054822384aaa47c29d64db50a2429617.png" width="1077"> 这里我修改了ds的值,让ds指向1000的地址,在将ax赋值1000:0000地址的值</p>
<p><img alt="" height="165" src="https://img-blog.csdnimg.cn/1193bfeefa97442ea3b5eabd785d9420.png" width="1086"></p>
<p> 从这里就可以知道了,数据的选择是ds决定的。</p>
<p></p>
<p></p>
<h2>段地址*10H +偏移地址=物理地址</h2>
<p><img alt="" height="505" src="https://img-blog.csdnimg.cn/5893f52c7bee4a5f8d02141d1afff427.png" width="1042"></p>
<p> 这里可以看到,这两块的地址是一模一样的,类似于:2000+2000和4000的内容是一模一样的,地址含义也一样</p>
<p></p>
<p>我一般认为是绝对地址和相对地址。就比如说这个,1*10H+0=10H,所以绝对地址是0000:0010,而0001就是段地址,0001:0000就是相对地址,有什么问题可以发出来。</p>
<h2>call指令</h2>
<p>call指令的作用,就是跳转,但是和jmp的区别是会将下一条指令的ip存到栈中</p>
<p>后面使用ret指令回来(将ip修改回来)</p>
<p><img alt="" height="404" src="https://img-blog.csdnimg.cn/afabdffef6d24a94a2328f6891372de6.png" width="1082"></p>
<p> </p>
<p>这里是运行了call指令,原先ip=100,后面栈中存放下一条指令也就是103。</p>
<p><img alt="" height="213" src="https://img-blog.csdnimg.cn/64269658fc0449959d41e209a17bfc7b.png" width="1040"></p>
<p> 这里用了ret,将ip修改回来了(通过栈)</p>
<p></p>
<h2>栈</h2>
<p>汇编里面的栈是通过ss:sp来指向的,用这里面的内存来存储数据</p>
<p>栈是先进后出,每次加进来的都要在标记的前面。</p>
<p>在这里面的内存形式0000:0000------->ffff:ffff ,所以每次入栈(push)sp=sp-2,而每次出栈就是(pop)sp=sp+2</p>
<p>栈的最大内存是sp=0时,因为sp=0-2=fffh,所以sp=0时栈内存最大</p>
<p>栈的内存表示,sp的起始到sp被我修改的值,其实是人为的认为,最常见认为sp的起始为0,sp的终止是10h,所以栈内存为10H</p>
<p>具体格式:push ax //是将ax里面的值存入ss:sp内存中</p>
<p>pop bx //是将栈里面的内容存入到bx寄存器中</p>
<p>类似的。</p>
<h2>psp区</h2>
<p>开始的256个字节是psp区,其作用是为了程序与系统进行通信的</p>
<p><img alt="" height="255" src="https://img-blog.csdnimg.cn/755bf87535914d4e9de37cf466c11e57.png" width="1058"></p>
<p> ds是取数据的,ds:0的数据并不是我写的程序的数据,一直到ds:0100才是,所以开始的256个字节是系统与程序进行通信的</p>
<p></p>
<p></p>
<p><img alt="" height="503" src="https://img-blog.csdnimg.cn/53b4593315a644ea9b8ed76972c8277e.png" width="1070"> <img alt="" height="525" src="https://img-blog.csdnimg.cn/e719f684fcab4dc08aeb9acf89564100.png" width="763"></p>
<p> 一个标准的asm(汇编)文件格式</p>
<p></p>
<pre>assume cs:code
code segment
mov ax,2000H ;在汇编语言中,;代表注释,mov代表赋值,add代表相加,pop出栈,push入栈,sub相减,jmp跳转,call
mov ss,ax ;,号右边给左边,这个,号类似于等号
mov sp,0 ;等等
add sp,10H
pop ax
pop bx
push ax
push bx ;交换ax,bx数据
pop ax
pop bx
;inc为增加的英文,inc bx,就是将bx加1,为了节约内存
mov ax,4C00H;程序返回
int 21H
code ends
end</pre>
<h2>loop循环以及用jmp实现类型loop</h2>
<p>loop比jmp多了一个次数操作,用cx来保存次数</p>
<p>jmp可以实现跳转</p>
<p>-p 可以直接执行完loop指令</p>
<p>-g 类似于go 后面要加地址</p>
<p><img alt="" height="651" src="https://img-blog.csdnimg.cn/bb6e06653b664494a668414b978f1944.png" width="1008"></p>
<p> loop也可以实现,但是loop需要注意的是cx=1,和cx=0的情况</p>
<p></p>
<p>cx=0时,会出现溢出。</p>
<p><img alt="" height="365" src="https://img-blog.csdnimg.cn/e375a80a71af45cfa62ae627a6ba8dfd.png" width="1030"></p>
<p> 当cx=1时,可以看出并没有循环,原因是走了一遍就算循环了一次,当cx=0时跳出循环,如果还没有走cx已经为0了,cx-1=FFFF,就要循环FFFF次。</p>
<p><img alt="" height="250" src="https://img-blog.csdnimg.cn/3c3f5e9c6a5f4daba05d43a4b9100125.png" width="1063"></p>
<p> </p>
<p></p>
<p></p>
<h3>用汇编指令写234*145</h3>
<pre>assume cs:code
code segment
mov ax,0
mov cx,145
addnumber:add ax,234 ;jmp也是和loop一个格式,除开cx次数
loop addnumber
mov ax,4C00H
int 21H
code ends
end</pre>
<p></p>
<p><img alt="" height="244" src="https://img-blog.csdnimg.cn/f9fc94045b1f4f62aa273f138649035f.png" width="993"></p>
<p><img alt="" height="278" src="https://img-blog.csdnimg.cn/2684323a930e462c90c67cb1e159bb51.png" width="398"> </p>
<p>debug的缺陷:有英文字母开头时,前面要加0</p>
<p></p>
<p>比如:mov ax,0ffffH</p>
<p>不加H时表示十进制。</p>
<h3>通过es和ds数据寄存器来交换数据实操</h3>
<pre>assume cs:code
code segment
mov ax,0fffH
mov ds,ax
mov ax,2000H
mov es,ax
mov cx,10H
mov bx,0
adderten: mov al,ds:
mov es:,al;es:是一个字节数据类型,不是字型数据类型
inc bx
loop adderten
mov ax,4C00H
int 21H
code ends
end</pre>
<h3>通过栈来复制两个地方的数据</h3>
<pre>assume cs:code
code segment
mov bx,0
mov cx,10H
adderten: mov ax,0fffH
mov ds,ax
mov ax,0
mov al,ds:
push ax
mov ax,2000H
mov ds,ax
pop ds:
inc bx
loop adderten
mov ax,4C00H
int 21H
code ends
end</pre>
<h3>dw 操作数据</h3>
<pre>assume cs:code
code segment
dw 1,2,3,4,5,6,7,8,9
start:
mov ax,0
mov bx,0
addax: add ax,cs: ;start 指定操作开始的位置
add bx,2 ;不用start在开头用jmp指令也行
loop addax
mov ax,4C00H
int 21H
code ends
end start</pre>
<p><img alt="" height="264" src="https://img-blog.csdnimg.cn/bad029d413fe42de827b98d4d041f103.png" width="1050"></p>
<p> </p>
<h3>dw和栈联用</h3>
<pre>assume cs:code
code segment
dw 1122H,2233H,3344H,4455H,5566H,6677H,7788H,8899H,9900H
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
start:
mov ax,cs
mov ss,ax
mov sp,32H ;栈内存是看字节形数据,所以应该是32H
mov bx,0
mov cx,9
addax: push cs:
add bx,2
loop addax
mov ax,4C00H
int 21H
code ends
end start</pre>
<p><img alt="" height="330" src="https://img-blog.csdnimg.cn/e37f04cb9e724aaea16ee61740f07b51.png" width="954"></p>
<p> </p>
<h3>数据段,指令段,stack段</h3>
<p>这样写可能会出一个bug,就是设置sp的大小就一定要和栈段一致,不然就会执行不知道什么的指令,那个时候就是严重型bug</p>
<pre>assume cs:code,ds:data,ss:stack
data segment
dw 1122H,2233H,3344H,4455H,5566H,6677H,7788H,8899H,9900H
data ends
stack segment
dw 0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0
stack ends
code segment
start:
mov ax,stack
mov ss,ax ;设置栈
mov sp,32 ;如果这样写了,设置栈的大小就一定要和栈段里面的要一致
mov ax,data
mov ds,ax ;设置数据段
mov bx,0 ;这样做就会将ds寄存器当作数据,ss:sp数据当作栈。
mov cx,9
addax:push data:
add bx,2
loop addax
mov ax,4C00H
int 21H
code ends
end start
</pre>
<h4>段的位置</h4>
<p>第一段一般是数据,第二段一般是栈,第三段则是指令</p>
<p>第一和第二段可以换位置,但是第三段不能换,涉及到数据覆盖问题</p>
<p>数据段位置:</p>
<p><img alt="" height="86" src="https://img-blog.csdnimg.cn/b454efeb5f414eac908fb6ce437c9d2e.png" width="1035"> </p>
<p></p>
<p>栈段位置:</p>
<p><img alt="" height="82" src="https://img-blog.csdnimg.cn/c63df65e0dfb4891a276ebaf4327ba80.png" width="797"> </p>
<p></p>
<p>指令段:</p>
<p><img alt="" height="72" src="https://img-blog.csdnimg.cn/a260c9999dcf40e885f6c7c15d7140c8.png" width="832"> </p>
<p></p>
<h4>段的空间大小</h4>
<p><img alt="" height="84" src="https://img-blog.csdnimg.cn/296401c1aef1449cb0fb798413fdbb4e.png" width="941"></p>
<p></p>
<p>就是16的倍数,如果比如9个字节长度,大小就是16个字节,如果说是23个字节长度,大小就是32个字节。</p>
<p>向大号取整。</p>
<p>比如说这个例子:就是数据是9个字型性长度,所以用了32个字节型长度。</p>
<h4>段的练习1:将两个数据段的数据相加,放到另外一个段中</h4>
<pre>assume cs:code
a segment
db 1,2,3,4,5,6,7,8
a ends
b segment
db 1,2,3,4,5,6,7,8 ;因为数据段寄存器不够了,所以先用栈保存一下位置,然后直接修改es寄存器将es寄存器改成c段那边,然 ;后赋值,后面pop掉es,就行了
b ends
c segment
db 0,0,0,0,0,0,0,0
c ends
code segment
start:
mov ax,a
mov ds,ax
mov cx,8
mov ax,b
mov es,ax
mov bx,0
mov ax,0
addax: push es
mov ax,ds:
add ax,es:
mov dx,c
mov es,dx
mov es:,ax
inc bx
pop es
loop addax
mov ax,4C00H
int 21H
code ends
end start
</pre>
<p> </p>
<p></p>
<h4>段的练习2:将a段中的前8个字型数据,逆序复制到b段中</h4>
<pre>assume cs:code
a segment
dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,b
mov ss,ax
mov sp,16
mov ax,a
mov ds,ax
mov bx,0
mov cx,8
adder: push ds:
add bx,2
loop adder
mov ax,4C00H
int 21H
code ends
end start
</pre>
<h2>bx,si,di都为偏移地址寄存器</h2>
<pre>assume cs:code
a segment
dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,a
mov ds,ax
mov si,1
mov di,2
mov bx,0
mov ax,ds: ;唯一的缺点就是不能用减法
add ax,ds:
code ends
end start</pre>
<h2>and,or运算符</h2>
<pre>assume cs:code
a segment
dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,00001111B
and ax,11110000B
code ends
end start
</pre>
<p> </p>
<p></p>
<pre>assume cs:code
a segment
dW 1,2,3,4,5,6,7,8,0AH,0BH,0CH,0DH,0FH,0FFH
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,00001111B
or ax,11110000B
mov ax,'a'
mov bx,'b'
code ends
end start
</pre>
<p><img alt="" height="321" src="https://img-blog.csdnimg.cn/732e7cf9ecb54727af89abc430ca1ffe.png" width="1080"></p>
<p> </p>
<p></p>
<h2>字符</h2>
<p><img alt="" height="570" src="https://img-blog.csdnimg.cn/d8f6f2b622c34bf2ac83dd03d2f925ff.png" width="1200"></p>
<p> </p>
<p><img alt="" height="513" src="https://img-blog.csdnimg.cn/30ede836cd8d45d98033ed5cb30bb40b.png" width="1200"> </p>
<p> </p>
<p></p>
<p></p>
<h3>同个字母的大写字母比小写字母要小32</h3>
<h3>将数据段nihao中的i变成大写I</h3>
<pre>assume cs:code
a segment
db 'nihao,I am you '
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,a
mov ds,ax
mov bx,1
mov al,ds:
andal,11011111B;注意不能在数据段进行and or操作
mov ds:,al
mov ax,4C00H
int 21H
code ends
end start</pre>
<p><img alt="" height="74" src="https://img-blog.csdnimg.cn/40f9cf2fcd9f4f0c81ac20354ef28632.png" width="1047"> </p>
<p></p>
<h3>将数据段中的所有数据变成大写</h3>
<pre>assume cs:code
a segment
db 'nihao,I am you '
a ends
b segment
dW 0,0,0,0,0,0,0,0
b ends
code segment
start: mov ax,a
mov ds,ax
mov bx,0
mov cx,14
adder: mov al,ds:
andal,11011111B
mov ds:,al
inc bx
loop adder
mov ax,4C00H
int 21H
code ends
end start
</pre>
<p></p>
<p>使用si和di偏移地址寄存器</p>
<p></p>
<h2>后面持续更新</h2><br><br>
来源:https://www.cnblogs.com/nanshaws/p/17892502.html
頁:
[1]