嗨饭先生 發表於 2020-1-29 14:26:00

汇编语言学习

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>汇编语言<ul><li>软件安装<ul><li>1.DOSBox</li><li>2.Vim</li></ul></li></ul></li><li>编译和链接<ul><li><ul><li><ul><li>将源代码 生成最终 的 exe 文件 然后执行</li></ul></li></ul></li></ul></li><li>进制<ul><li>10进制</li><li>2进制</li><li>进制快速转换</li><li>字节转换</li><li>小结</li></ul></li><li>寄存器<ul><li>通用寄存器</li><li>(地址寄存器)指令寄存器 CS(段地址)和IP(偏移地址)</li><li>指令的执行过程</li></ul></li><li>debug</li><li>寄存器(内存访问)<ul><li><ul><li><ul><li>3个段</li></ul></li></ul></li><li>数据段<ul><li>1. 字的存储</li><li>2.</li><li>3. mov,add,sub 指令</li><li>4. -d 段地址:偏移地址</li><li>5. 在内存中存放自己定义的数据,通过 <em><strong>ds和[]</strong></em> 来 让CPU访问数据</li></ul></li><li>代码段<ul><li>1. 段地址存放在cs寄存器中</li><li>2. 偏移地址存放在ip寄存器当中</li><li>3. 内存中存放代码</li><li>4. 修改cs:ip中的值就可使CPU执行代码</li></ul></li><li>栈段<ul><li>1. 栈的作用</li><li>2. 栈的寄存器ss:sp</li><li>3. 操作指令push&amp;ip</li><li>4. 处理数据时要 ,临时存放数据</li><li>5. 修改ss:sp中的值,决定栈顶位置,CPU在执行的过程中把我们定义的栈段当作栈使用</li><li>6. 一段连续的内存地址</li><li>7. 栈的容量的最大极限</li><li>8.每执行 一条 -t 指令 就会将寄存器的值保存到 栈中</li></ul></li><li>内存的安全访问</li></ul></li><li>承上启下</li><li>第一个程序<ul><li>编译和链接</li><li>程序的跟踪 debug + 程序名</li><li>快速编译</li><li>偏移地址寄存器 <em><strong>bx</strong></em></li></ul></li><li>自己分配内存<ul><li>自己分配内存</li><li>总结</li></ul></li><li>定位内存地址的方法<ul><li>and 和 or</li><li>以字符的形式给出数据</li><li>大小写转换</li><li></li><li>SI 和 DI</li><li>         和 </li><li> 和 </li></ul></li><li>数据处理的两个基本问题<ul><li>bx,si,di和bp</li><li>指令要处理的数据</li><li>数据位置的表达</li><li>数据的长度</li><li>div 指令</li><li>伪指令 dd (占两个字)</li><li>dup</li></ul></li><li>转移指令<ul><li>操作符 offset</li><li>jmp 指令<ul><li>jmp short 标号</li><li>jmp near ptr 标号</li><li>jmp far ptr 标号</li><li>在内存中转移<ul><li>jmp word ptr 标号</li><li>jmp dword ptr 标号</li></ul></li><li>jcxz (短转移)</li><li>loop(短转移)</li></ul></li></ul></li><li>ret 和 call<ul><li>ret(用栈中的数据)</li><li>call(不能实现短转移)<ul><li>1.根据位移进行转移</li><li>2.转移目的地址在指令中</li><li>3.转移地址在寄存器中<ul><li>2</li></ul></li></ul></li><li>call 和 ret 共同应用<ul><li>批量数据处理</li><li>寄存器冲突问题</li></ul></li><li>mul<ul><li>1. 8位</li><li>2. 16位</li></ul></li><li>模块化程序设计<ul><li>参数和结果的传递</li></ul></li></ul></li><li>标志寄存器</li><li>内中断<ul><li>1.产生</li><li>2. 中断处理程序</li><li>3. 中断向量表</li><li>4.中断的过程</li><li>5.中断处理程序和iret指令</li><li>6. 除法错误中断的处理</li><li>7. 编程处理0号中断</li></ul></li><li>端口<ul><li>1. 端口读写指令</li><li>2.CMOS RAM</li><li>3.shl,shr</li></ul></li></ul></div><p></p>
<h1 id="汇编语言">汇编语言</h1>
<ul>
<li>日期 19.07.19</li>
</ul>
<h2 id="软件安装">软件安装</h2>
<hr>
<h3 id="1dosbox">1.DOSBox</h3>
<ul>
<li>
<ol>
<li>无脑下一步</li>
</ol>
</li>
<li>
<ol start="2">
<li>修改配置文件<br>
添加以下命令</li>
</ol>
</li>
</ul>
<pre><code>mount c: d:\asm
c:
//d盘下的文件是自行创建其中包含debug.exe就可以了
</code></pre>
<h3 id="2vim">2.Vim</h3>
<ul>
<li>
<ol>
<li>安装完后打开其文件位置</li>
</ol>
</li>
<li>
<ol start="2">
<li>修改配置文件<br>
在开头写入简单的配置文件</li>
</ol>
</li>
</ul>
<pre><code>set number
color evening
//保存退出
</code></pre>
<h1 id="编译和链接">编译和链接</h1>
<hr>
<h4 id="将源代码-生成最终-的-exe-文件-然后执行">将源代码 生成最终 的 exe 文件 然后执行</h4>
<ul>
<li>这一部分刚开始跟上做就好了,不用了解清楚</li>
</ul>
<blockquote>
<p>DOSBox代码</p>
<pre><code>masm t1;
link t1;
// t1 为自己创建的asm文件
//在创建txt文件把后缀改为asm
//用vim编辑
</code></pre>
<p>asm文件代码</p>
<pre><code class="language-as">assume cs:code
</code></pre>
</blockquote>
<pre><code class="language-assembly">code segment



                mov bx,0B800H
                mov es,bx
               
                mov bx,160*10 + 40*2

                mov word ptr es:,5535H

                mov ax,4C00H
                int 21H



code ends
end
</code></pre>
<h1 id="进制">进制</h1>
<hr>
<h2 id="10进制">10进制</h2>
<blockquote>
<p>437-&gt;&gt;&gt;</p>
<p></p><div class="math display">\[4* 100+3* 10+7* 1
\]</div><p></p><p></p><div class="math display">\[4*10^2+3*10^1+7*10^0
\]</div><p></p><p>0.1.2.3就是他在数字中的位置</p>
</blockquote>
<h2 id="2进制">2进制</h2>
<blockquote>
<p>111-&gt;&gt;</p>
<p></p><div class="math display">\[1*2^2+1*2^1+1*2^0$$ &gt;&gt;转换成10进制

\]</div><p></p></blockquote>
<table>
<thead>
<tr>
<th>数字</th>
<th>1</th>
<th>0</th>
</tr>
</thead>
<tbody>
<tr>
<td>含义</td>
<td>有</td>
<td>无</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>位置</th>
<th>2</th>
<th>1</th>
<th>0</th>
</tr>
</thead>
<tbody>
<tr>
<td>有代表</td>
<td>4</td>
<td>2</td>
<td>1</td>
</tr>
</tbody>
</table>
<h2 id="进制快速转换">进制快速转换</h2>
<blockquote>
<p>拆分</p>
</blockquote>
<h2 id="字节转换">字节转换</h2>
<blockquote>
<p></p><div class="math display">\[1 byte = 8 bit
\]</div><p></p><p></p><div class="math display">\[1 KB   = 1024 byte$$      &gt;&gt;                      $$1KB = 2^{10} byte
\]</div><p></p><p></p><div class="math display">\[1 MB   = 1024 * 1KB$$      1MB = 1024 * 1024 byte &gt;&gt; $$1MB = 2^{20} byte
\]</div><p></p><p></p><div class="math display">\[1 GB   = 1024 * 1MB$$            &gt;&gt;                  $$1GB = 2^{30} byte
\]</div><p></p></blockquote>
<h2 id="小结">小结</h2>
<blockquote>
<ol>
<li>汇编指令是 机器指令的 注记符,同机器指令一一对应</li>
<li>每一种CPU都有自己的汇编指令集</li>
<li>CPU 可以直接使用的 信息 在存储器中 存放<br>
4.在存储器中指令和数据没用任何区别, 都是二进制数<br>
5.存储器单元从 0 开始 编号<br>
6.一个 存储单元 可以存储 8 个 bit 即 8 为二进制数<br>
7.1byte=8bit 1KB=1024byte 1MB=1024KB 1GB=1024MB<br>
总线</li>
</ol>
<blockquote>
<p>地址总线 决定 CPU 的 寻址能力<br>
数据总线 决定 CPU 的 一次传输数据量<br>
控制总线 决定 CPU 的 对其他器件的控制能力</p>
</blockquote>
</blockquote>
<h1 id="寄存器">寄存器</h1>
<hr>
<ol>
<li>
<p>小例子<br>
1.1 B800:0400 回车<br>
1.2 1空格 1空格<br>
1.3 2空格 2空格<br>
1.4    ...</p>
</li>
<li>
<p>汇编程序员 就是 通过 汇编语言 中的 汇编指令 去修改 寄存器的值 从而 控制 CPU 控制整个计算机</p>
</li>
</ol>
<h2 id="通用寄存器">通用寄存器</h2>
<blockquote>
<p><strong>AX,BX,CX,DX</strong></p>
<ol>
<li>他们各自可分为两个 8 位寄存器(only)<p></p><div class="math display">\[ax=ah+al$$ $$(h==high,l==low)
\]</div><p></p></li>
<li>1 byte = 8 bit(8位寄存器)<mark>字节型数据<br>
2 byte =16 bit(16位寄存器)</mark>字型数据<code>2个字节</code><br>
一个字型数据==2个字节型数据=高位字节+低位字</li>
<li><strong>数据与寄存器之间 要 保持一致性,8位寄存器给8位数据,16为寄存器给16位数据</strong><br>
<mark>不区</mark>分大小写</li>
</ol>
</blockquote>
<h2 id="地址寄存器指令寄存器-cs段地址和ip偏移地址">(地址寄存器)指令寄存器 CS(段地址)和IP(偏移地址)</h2>
<blockquote>
<p>jmp指令 jmp 2000:0 <mark><mark>&gt; cs</mark>2000,ip</mark>=0;</p>
<blockquote>
<p>mov ax,1000<br>
jmp ax<br>
==&gt; ip=1000;</p>
</blockquote>
<p>只能用jmp指令修改cs,ip</p>
<p>1.CPU从cs:ip 所指的内存单元中读取内容,存取到 指令缓存器当中<br>
2.然后IP跳转到下一个指令位置,并且在执行指令缓存器当中的指令<br>
3.重复1。</p>
<table>
<thead>
<tr>
<th>段地址寄存器</th>
<th>偏移地址寄存器</th>
</tr>
</thead>
<tbody>
<tr>
<td>ds(内存),es,ss(栈),cs</td>
<td>sp(栈),bp,si,di,ip,bx</td>
</tr>
</tbody>
</table>
</blockquote>
<h2 id="指令的执行过程">指令的执行过程</h2>
<ol>
<li>CPU从cs:ip所指向的内存单元 读取 指令 然后 存放到 指令缓存器当中</li>
<li>IP = IP + 所读指令的长度,从而指向下一条指令</li>
<li>执行指令缓存器的内容,回到步骤1</li>
</ol>
<h1 id="debug">debug</h1>
<p><strong>-r 查看和修改寄存器中的内容</strong></p>
<p>-r cs<br>
cs value<br>
enter</p>
<p><strong>-d 查看内存中的内容</strong>段地址加偏移地址</p>
<blockquote>
<p>-d ss:00</p>
</blockquote>
<p><strong>-v 将机器指令翻译成汇编指令</strong><br>
<strong>-a 以汇编指令的格式 在内存中写入一条汇编指令</strong> 每次debug都的写<br>
<strong>-t 执行当前 cs:ip 所指的机器指令</strong> 代码段<br>
<strong>-e 可以改写 内存中的内容(数据)</strong></p>
<p><strong>-p 快速执行完loop 指令</strong><br>
<strong>-g 地址 ==== 一直执行到 地址 的 位置</strong></p>
<h1 id="寄存器内存访问">寄存器(内存访问)</h1>
<hr>
<h4 id="3个段">3个段</h4>
<hr>
<h2 id="数据段">数据段</h2>
<h3 id="1-字的存储">1. 字的存储</h3>
<blockquote>
<p>一次存放两个字节</p>
</blockquote>
<h3 id="2">2.</h3>
<blockquote>
<p>内存地址由 <strong>段地址</strong> 和 <strong>偏移地址</strong> 构成<br>
其中段地址默认保存在DS寄存器当中<br>
偏移地址由 <strong></strong> 保存告知</p>
</blockquote>
<h3 id="3-movaddsub-指令">3. mov,add,sub 指令</h3>
<p><img src="https://raw.githubusercontent.com/bgst009/test/master/mem.png" alt="mov指令" loading="lazy"></p>
<h3 id="4--d-段地址偏移地址">4. -d 段地址:偏移地址</h3>
<h3 id="5-在内存中存放自己定义的数据通过-ds和-来-让cpu访问数据">5. 在内存中存放自己定义的数据,通过 <em><strong>ds和[]</strong></em> 来 让CPU访问数据</h3>
<h2 id="代码段">代码段</h2>
<h3 id="1-段地址存放在cs寄存器中">1. 段地址存放在cs寄存器中</h3>
<h3 id="2-偏移地址存放在ip寄存器当中">2. 偏移地址存放在ip寄存器当中</h3>
<h3 id="3-内存中存放代码">3. 内存中存放代码</h3>
<h3 id="4-修改csip中的值就可使cpu执行代码">4. 修改cs:ip中的值就可使CPU执行代码</h3>
<h2 id="栈段">栈段</h2>
<h3 id="1-栈的作用">1. 栈的作用</h3>
<ol>
<li>临时性保存数据</li>
<li>进行数据交换</li>
</ol>
<pre><code>-a
mov ax,1000
mov bx,2000
push ax
push bx
pop ax
pop bx
</code></pre>
<h3 id="2-栈的寄存器sssp">2. 栈的寄存器ss:sp</h3>
<h3 id="3-操作指令puship">3. 操作指令push&amp;ip</h3>
<blockquote>
<p>push 执行过程</p>
<blockquote>
<p>1.sp=sp-2(栈顶标记)<br>
2.传入字型数据</p>
</blockquote>
<p>pop 执行过程</p>
<blockquote>
<p>1.传出字或字节<br>
2.sp=sp+2(栈顶标记)</p>
</blockquote>
<p>栈顶标记 在 数据(内存地址)的上面 的 内存地址<br>
sp 偏移地址寄存器 ss 段地址寄存器</p>
</blockquote>
<h3 id="4-处理数据时要-临时存放数据">4. 处理数据时要 ,临时存放数据</h3>
<h3 id="5-修改sssp中的值决定栈顶位置cpu在执行的过程中把我们定义的栈段当作栈使用">5. 修改ss:sp中的值,决定栈顶位置,CPU在执行的过程中把我们定义的栈段当作栈使用</h3>
<h3 id="6-一段连续的内存地址">6. 一段连续的内存地址</h3>
<h3 id="7-栈的容量的最大极限">7. 栈的容量的最大极限</h3>
<blockquote>
<p>sp 的变化范围 0~ffffH 32768 个字型数据<br>
call 将指令IP 保存到内存的哪里?ret 可以拿回</p>
<blockquote>
<p>保存到栈中 为了让 ret 从栈中取回</p>
</blockquote>
</blockquote>
<h3 id="8每执行-一条--t-指令-就会将寄存器的值保存到-栈中">8.每执行 一条 -t 指令 就会将寄存器的值保存到 栈中</h3>
<h2 id="内存的安全访问">内存的安全访问</h2>
<ol>
<li>安全空间 0:200~0: 2ffH</li>
<li>内存分配的时间 1. 系统加载程序的时候 为程序分配的内存。2. 程序执行过程中,向系统再去要内存空间</li>
</ol>
<h1 id="承上启下">承上启下</h1>
<hr>
<ul>
<li>我们可以把内存任意的划分为 栈,数据,指令 ,他们可以是同一块内存,亦可以是不同的内存</li>
<li>cpu 通过 ss:sp 所指向的 内存作为 栈</li>
<li>ds:[] 所指向的 内存 作为数据</li>
<li>cs:ip 所指向的 内存 作为指令</li>
</ul>
<p><strong>指令从哪里?数据从哪来?临时性的数据存放到哪里?</strong></p>
<h1 id="第一个程序">第一个程序</h1>
<hr>
<h2 id="编译和链接-1">编译和链接</h2>
<ol>
<li>编译 masm .mas --&gt; .obj</li>
<li>链接 link .obj --&gt; .exe</li>
</ol>
<blockquote>
<p>exe 文件 的描述信息中 保存的程序入口 地址<br>
然后 系统 通过 描述文件 来设置 cs:ip 和 其它内存</p>
</blockquote>
<blockquote>
<p>asm 文件 -- 汇编语言(<strong>1.汇编指令2.伪指令3.符号体系</strong>)</p>
<ol>
<li>汇编指令 由编译器 翻译成010101 的机器指令 最后由 <em><strong>CPU</strong></em> 执行</li>
<li>伪指令和符号体系 由编译器执行</li>
</ol>
</blockquote>
<blockquote>
<ul>
<li>程序返回功能<br>
把系统加载程序的时候 给程序分配的内存 , 设置的寄存器 返还给系统,因为 系统资源 是有限的</li>
</ul>
</blockquote>
<pre><code> mov ax,4c00
int 21H
</code></pre>
<h2 id="程序的跟踪-debug--程序名">程序的跟踪 debug + 程序名</h2>
<ul>
<li>
<p>p 执行 int 指令</p>
</li>
<li>
<p>q 退出</p>
</li>
<li>
<p>cx == 程序长度</p>
</li>
<li>
<p>PSP区 从 <em><strong>ds:0</strong></em> 开始的 256 个字节</p>
</li>
</ul>
<h2 id="快速编译">快速编译</h2>
<ul>
<li>字母型数字前面 必须加 0;</li>
</ul>
<blockquote>
<p>默认代码(目前)</p>
</blockquote>
<pre><code>assum cs:code

code segment
   
   ;填写内容
   
   mov ax,4c00H
   int 21H

code ends

end
</code></pre>
<h2 id="偏移地址寄存器-bx">偏移地址寄存器 <em><strong>bx</strong></em></h2>
<h1 id="自己分配内存">自己分配内存</h1>
<h2 id="自己分配内存-1">自己分配内存</h2>
<ul>
<li>一个 segement 最少占据 16 个字节</li>
<li>
<blockquote>
<p>假设 数据段 有 N个字节 则 实际占用 $$(N/16 + 1)*16$$ 个</p>
</blockquote>
</li>
<li>都是 16 的倍数</li>
</ul>
<pre><code class="language-Assembly">//实验5
assume cs:codesg

a segment
                db 1,2,3,4,5,6,7,8
a ends

b segment
                db 1,2,3,4,5,6,7,8
b ends

c segment
                db 0,0,0,0,0,0,0,0
c ends

codesg segment
       
start:
               
               
                mov ax,c
                mov es,ax

               
                sub cx,cx
                sub bx,bx
                add cx,8

addnum: mov ax,a
                mov ds,ax
               
                sub dx,dx
       
                mov dl,ds: ;拿出第一个数据
               
                mov ax,b
                mov ds,ax
               
                add dl,ds:;拿出第二个数据,并且相加
               
                mov es:,dl
               
                inc bx
       
                loop addnum


          
        mov ax,4c00h
        int 21h

codesg ends

end start
</code></pre>
<h2 id="总结">总结</h2>
<ul>
<li>db 字节型</li>
<li>dw 字型</li>
</ul>
<h1 id="定位内存地址的方法">定位内存地址的方法</h1>
<h2 id="and-和-or">and 和 or</h2>
<ol>
<li>and 逻辑与0置为0
<ol>
<li>全为 <strong>1</strong> 才出 <strong>1</strong> 否则全部为 <strong>0</strong></li>
<li>可用于 对 二进制位的数字 设 <strong>0</strong></li>
</ol>
</li>
<li>or 逻辑或   1置为1
<ol>
<li>只要有<strong>1</strong> 就为 <strong>1</strong></li>
<li>可用于对 二进制数字设 <strong>1</strong></li>
</ol>
</li>
</ol>
<h2 id="以字符的形式给出数据">以字符的形式给出数据</h2>
<ul>
<li>like‘………’         其中单引号包含的 内容 编译器将把 其中的内容 转化为相应的 ASCII</li>
</ul>
<h2 id="大小写转换">大小写转换</h2>
<p>and 置为大写 1101 1111b</p>
<p>or    置为小写 0100 0000b</p>
<h2 id="bxidata"></h2>
<ul>
<li>idata 是立即数</li>
</ul>
<blockquote>
<p>常用格式</p>
<ol>
<li>mov ax,</li>
<li>mov ax,200</li>
<li>mov ax,.200</li>
</ol>
</blockquote>
<ul>
<li>可以处理数组</li>
</ul>
<h2 id="si-和-di">SI 和 DI</h2>
<ul>
<li>类似于<strong>BX</strong> <mark>但是</mark> 不能 分成两个 8 为寄存器</li>
<li>全为偏移地址寄存器 <strong><mark>bx为基址寄存器</mark></strong></li>
</ul>
<h2 id="bxsi-和-bxdi">         和 </h2>
<blockquote>
<p>常用格式</p>
<p><strong>mov ax, </strong></p>
</blockquote>
<h2 id="bxsiidata-和-bxdiidata"> 和 </h2>
<h1 id="数据处理的两个基本问题">数据处理的两个基本问题</h1>
<blockquote>
<p><strong>sreg 段地址寄存器</strong></p>
<p><strong>reg</strong> 寄存器</p>
</blockquote>
<h2 id="bxsidi和bp">bx,si,di和bp</h2>
<ul>
<li>bx si/di组合</li>
<li>bp si/di组合</li>
</ul>
<h2 id="指令要处理的数据">指令要处理的数据</h2>
<ol>
<li><strong>保存在CPU</strong></li>
<li><strong>在内存中</strong></li>
<li><strong>在端口中</strong></li>
</ol>
<h2 id="数据位置的表达">数据位置的表达</h2>
<ol>
<li>立即数(idata)</li>
<li>寄存器</li>
<li>段地址加偏移地址</li>
</ol>
<h2 id="数据的长度">数据的长度</h2>
<ul>
<li>byte 和 word</li>
</ul>
<blockquote>
<p>在处理数据的时候要 告知 CPU 要处理的数据有多大可以通过一些方法来告知</p>
<p><strong>1. 通过寄存器来指明 如 <mark>ax</mark>,代表对word操作而 <mark>al</mark>,代表对byte 操作</strong></p>
<p><strong>2. 无寄存器 则用 <mark>X ptr</mark> 来表示 X 为byte 或者 word如 : mov word ptr ds:,1</strong></p>
<p><strong>3.用 push or pop 就不用 声明 因为 栈就是 对字进行操作</strong></p>
</blockquote>
<h2 id="div-指令">div 指令</h2>
<ul>
<li><strong>除数</strong> 有8位和16位 在一个reg或内存单元中</li>
<li><strong>被除数</strong> 默认 放在 <mark>ax(16位)</mark> 或者 <mark>dx(高16位) 和 ax(低16位)</mark> 中</li>
<li><strong>结果</strong><mark>al(商) ah(余数)</mark> 或者 <mark>ax(商) dx(余数)</mark></li>
</ul>
<h2 id="伪指令-dd-占两个字">伪指令 dd (占两个字)</h2>
<ul>
<li>相当于 两个 <mark>dw</mark></li>
<li>四个 <mark>db</mark></li>
</ul>
<h2 id="dup">dup</h2>
<p><strong>用来重复数据</strong></p>
<ul>
<li>db 3 dup (0)==&gt; db 0 ,0, 0</li>
</ul>
<h1 id="转移指令">转移指令</h1>
<h2 id="操作符-offset">操作符 offset</h2>
<ul>
<li>取得标号的偏移地址</li>
</ul>
<h2 id="jmp-指令">jmp 指令</h2>
<hr>
<ul>
<li>无条件转移指令</li>
<li>可同时修改 cs 和 ip 或者 ip</li>
</ul>
<h3 id="jmp-short-标号">jmp short 标号</h3>
<hr>
<ul>
<li>在编译是就已经处理好 要偏移的地址</li>
<li>无论 本 命令在哪 只有 偏移地址</li>
</ul>
<h3 id="jmp-near-ptr-标号">jmp near ptr 标号</h3>
<hr>
<ul>
<li>段内短转移</li>
</ul>
<h3 id="jmp-far-ptr-标号">jmp far ptr 标号</h3>
<hr>
<ul>
<li>同时修改 cs 和 ip</li>
</ul>
<h3 id="在内存中转移">在内存中转移</h3>
<hr>
<h4 id="jmp-word-ptr-标号">jmp word ptr 标号</h4>
<ul>
<li>jmp word ptr ds:</li>
<li>只修改 IP</li>
<li>段内转移</li>
</ul>
<h4 id="jmp-dword-ptr-标号">jmp dword ptr 标号</h4>
<ul>
<li>段间转移</li>
<li>ip,cs</li>
</ul>
<h3 id="jcxz-短转移">jcxz (短转移)</h3>
<hr>
<ul>
<li>jmp cx zero</li>
<li>只有在cx 为0 的情况下 才 执行 转移</li>
</ul>
<h3 id="loop短转移">loop(短转移)</h3>
<hr>
<ul>
<li>cx 不为0 执行loop</li>
</ul>
<h1 id="ret-和-call">ret 和 call</h1>
<hr>
<ul>
<li>指令执行过程
<ul>
<li><img src="%E6%B1%87%E7%BC%96.assets/20190928095954.png" alt="" loading="lazy"></li>
</ul>
</li>
</ul>
<p><strong>通过栈中的数据来修改 cs和 ip 同时还会 修改栈顶标志</strong></p>
<h2 id="ret用栈中的数据">ret(用栈中的数据)</h2>
<hr>
<ul>
<li><strong>弹栈</strong></li>
</ul>
<ol>
<li>近转移 ret 修改 IP <em><strong>pop ip</strong></em>
<ol>
<li><span class="math inline">\((ip)=((ss)*16+(sp))\)</span></li>
<li><span class="math inline">\((sp)=(sp)+2\)</span></li>
</ol>
</li>
<li>远转移 retf 修改 cs:ip <em><strong>pop ip,pop cs</strong></em>
<ol>
<li><span class="math inline">\((ip)=((ss)*16+(sp))\)</span></li>
<li><span class="math inline">\((sp)=(sp)+2\)</span></li>
<li><span class="math inline">\((cs)=((ss)*16+(sp))\)</span></li>
<li><span class="math inline">\((sp)=(sp)+2\)</span></li>
</ol>
</li>
</ol>
<h2 id="call不能实现短转移">call(不能实现短转移)</h2>
<hr>
<ul>
<li>类似<strong>jmp</strong></li>
<li>call程序处理的数据一般要进行压栈</li>
</ul>
<h3 id="1根据位移进行转移">1.根据位移进行转移</h3>
<hr>
<pre><code class="language-assembly">push ip
jmp near ptr 标号
</code></pre>
<ul>
<li>执行过程 原理
<ul>
<li>call下一条指令的IP压栈后,转到标号处</li>
</ul>
</li>
</ul>
<h3 id="2转移目的地址在指令中">2.转移目的地址在指令中</h3>
<hr>
<pre><code class="language-assembly">call far ptr
</code></pre>
<ul>
<li>执行过程 原理
<ul>
<li>call下一条指令的CS:IP压栈后,转到标号处</li>
</ul>
</li>
</ul>
<h3 id="3转移地址在寄存器中">3.转移地址在寄存器中</h3>
<hr>
<p>​```assembly<br>
call 16 位 reg</p>
<pre><code>
- 执行过程 原理
- call下一条指令的IP压栈后,转到==reg== 处

### 4. 转移地址在内存中

----

#### 1

-----

```assembly
call word ptr 内存单元地址
</code></pre>
<ul>
<li>执行过程 原理
<ul>
<li>call下一条指令的IP压栈后,转到<mark>内存单元地址</mark></li>
</ul>
</li>
</ul>
<h4 id="2-1">2</h4>
<hr>
<pre><code class="language-assembly">call dword ptr 内存单元地址
</code></pre>
<ul>
<li>执行过程 原理
<ul>
<li>call下一条指令的CS:IP压栈后,转到标号处</li>
</ul>
</li>
</ul>
<h2 id="call-和-ret-共同应用">call 和 ret 共同应用</h2>
<hr>
<ul>
<li>就像函数调用</li>
</ul>
<h3 id="批量数据处理">批量数据处理</h3>
<hr>
<pre><code class="language-assembly">assume cs:code,ds:data,ss:stack

data segment       
        db 'conversation'
data ends

stack segment
        db 16 dup(0)
stack ends

code segment


        start:mov ax,data
                        mov ds,ax
                        mov si,0
                        mov cx,12
                        call capital
                        mov ax,4c00h
                        int 21h
                       
        capital: and byte ptr ds:,11011111b
                       inc si;
                       loop capital
                       ret


code ends



end start
</code></pre>
<h3 id="寄存器冲突问题">寄存器冲突问题</h3>
<hr>
<ul>
<li>在子程序执行开头,把所需要用到的寄存器压栈</li>
<li>在子程序完成后,从栈中弹出各个寄存其的值</li>
</ul>
<pre><code class="language-assembly">assume cs:code,ds:data,ss:stack

data segment       
        db 'word',0
        db 'unix',0
        db 'wind',0
        db 'good',0
data ends

stack segment
        db 128 dup(0)
stack ends

code segment


        start:mov ax,data
                        mov ds,ax
                       
                        mov cx,4
                        mov bx,0
                       
        s:      mov di,bx
                        call capital
                        add bx,5
                        loop s
                       
                        mov ax,4c00h
                        int 21h
       
        capital: push cx;执行子程序前压栈
                       push si
                       
        change:       mov cl,ds:
                       mov ch,0
                       jcxz ok
                       and byte ptr ds:,11011111b
                       inc si
                       jmp change
                       
                ok:       pop si;执行完后弹栈
                       pop cx
                       ret


code ends



end start
</code></pre>
<h2 id="mul">mul</h2>
<hr>
<h3 id="1-8位">1. 8位</h3>
<hr>
<blockquote>
<p>一个默认放在<mark>AL</mark>,另一个放在<mark>内存字节单元</mark>或者<mark>8位reg</mark>。</p>
<p>结果 默认 <mark>AX</mark>。</p>
</blockquote>
<h3 id="2-16位">2. 16位</h3>
<blockquote>
<p>一个默认放在<mark>AX</mark>,另一个放在<mark>内存字单元</mark>或者<mark>16位reg</mark>。</p>
<p>结果 默认 高位在<mark>DX</mark> ,低位在<mark>AX</mark>。</p>
</blockquote>
<h2 id="模块化程序设计">模块化程序设计</h2>
<hr>
<ul>
<li>通过<mark>ret</mark>,<mark>call</mark>.</li>
</ul>
<h3 id="参数和结果的传递">参数和结果的传递</h3>
<pre><code class="language-assembly">assume cs:code,ds:data,ss:stack

data segment       
        dw 1,2,3,4,5,6,7,8
        dd 0,0,0,0,0,0,0,0
        db 'word',0
        db 'unix',0
        db 'wind',0
        db 'good',0
data ends

stack segment
        db 128 dup(0)
stack ends

code segment


        start:mov ax,data
                        mov ds,ax
                        mov si,0
                        mov bp,0
                        call r_start
                       
                       
                        mov ax,4c00h
                        int 21h

                       
        r_start:        mov bx,ds:
                                call cube
                                mov ds:,ax
                                add si,2
                                add bp,4
                                loop r_start
                                ret
                       
                cube:        mov ax,bx
                                mul bx
                                mul bx
                                ret

</code></pre>
<h1 id="标志寄存器">标志寄存器</h1>
<hr>
<blockquote>
<img src="%E6%B1%87%E7%BC%96.assets/1573010421984.png" alt="1573010421984" style="zoom: 80%">
</blockquote>
<hr>
<ul>
<li>
<p>CF标志位<strong>Carry Flag</strong></p>
<ul>
<li><img src="%E6%B1%87%E7%BC%96.assets/1573010380365.png" alt="1573010380365" loading="lazy"></li>
<li>进位(最高位进位)add</li>
<li>和运算相关的指令会影响标志位 like <mark>add , sub</mark></li>
<li>把操作数当作无符号数字</li>
</ul>
</li>
<li>
<p>ZF标志位<strong>Zero Flag</strong></p>
<ul>
<li><img src="%E6%B1%87%E7%BC%96.assets/1573010356660.png" alt="1573010356660" loading="lazy"></li>
</ul>
</li>
<li>
<p>判断相等</p>
</li>
<li>
<p>最后结果是否为零</p>
</li>
<li>
<p>PF标志位<strong>pairty Flag</strong></p>
<ul>
<li>一的个数是否位偶数0 or 奇数1</li>
<li><img src="%E6%B1%87%E7%BC%96.assets/1573011155062.png" alt="1573011155062" loading="lazy"></li>
</ul>
</li>
<li>
<p>SF标志位<strong>Sign Flag</strong></p>
<ul>
<li>正0负1</li>
<li><img src="%E6%B1%87%E7%BC%96.assets/1573011683986.png" alt="1573011683986" loading="lazy"></li>
<li>计算的结果看陈整数和负数</li>
<li>add sub 影响sf</li>
<li>mul 不影响sf</li>
</ul>
</li>
<li>
<p>OF标志位<strong>Overflow</strong></p>
<ul>
<li><img src="%E6%B1%87%E7%BC%96.assets/1573087099543.png" alt="1573087099543" loading="lazy"></li>
<li>运算过程中看是否溢出</li>
<li>两个操作数都当做有符号 运算过程中决定是否溢出</li>
</ul>
</li>
<li>
<p>adc 带进位的加法寄存器</p>
<ul>
<li>可以对更大的数字进行加法运算</li>
</ul>
</li>
<li>
<p>sbb 带借位减法</p>
<ul>
<li>实现对更大数的减法</li>
</ul>
</li>
<li>
<p>cmp 比较指令</p>
<ul>
<li>
<p>类似于减法指令 只是不保存结果,只是影响相关的标志位寄存器</p>
</li>
<li>
<p>可以判断两个操作数的大小 通过 sf of 标志位</p>
<blockquote>
<table>
<thead>
<tr>
<th style="text-align: center">sf</th>
<th style="text-align: center">of</th>
<th style="text-align: center">大小</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">1</td>
<td style="text-align: center">0</td>
<td style="text-align: center">1&lt;2</td>
</tr>
<tr>
<td style="text-align: center">0</td>
<td style="text-align: center">1</td>
<td style="text-align: center">1&lt;2</td>
</tr>
<tr>
<td style="text-align: center">1</td>
<td style="text-align: center">1</td>
<td style="text-align: center">1&gt;2</td>
</tr>
<tr>
<td style="text-align: center">0</td>
<td style="text-align: center">0</td>
<td style="text-align: center">1&gt;2</td>
</tr>
</tbody>
</table>
</blockquote>
</li>
</ul>
</li>
<li>
<p>检测比较结果的转移指令</p>
<ul>
<li>和 cmp指令配合使用
<ul>
<li>
<blockquote>
<table>
<thead>
<tr>
<th style="text-align: center">指令</th>
<th style="text-align: center">含义</th>
<th style="text-align: center">检测相关的标志位</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">je</td>
<td style="text-align: center">equal</td>
<td style="text-align: center">zf=1</td>
</tr>
<tr>
<td style="text-align: center">jne</td>
<td style="text-align: center">not equal</td>
<td style="text-align: center">zf=0</td>
</tr>
<tr>
<td style="text-align: center">jb</td>
<td style="text-align: center">below</td>
<td style="text-align: center">cf=0</td>
</tr>
<tr>
<td style="text-align: center">jnb</td>
<td style="text-align: center">not below</td>
<td style="text-align: center">cf=1</td>
</tr>
<tr>
<td style="text-align: center">ja</td>
<td style="text-align: center">above</td>
<td style="text-align: center">cf=0 &amp;&amp; zf=1</td>
</tr>
<tr>
<td style="text-align: center">jna</td>
<td style="text-align: center">not above</td>
<td style="text-align: center">cf=1 || zf=1</td>
</tr>
</tbody>
</table>
</blockquote>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>DF 标志和串传送指令</p>
<ul>
<li>
<p>movsb</p>
</li>
<li>
<p>movsw</p>
</li>
<li>
<p>配合rep 使用 rep like loop 由cx 的大小决定 执行 上述 两条指令的 次数</p>
<ul>
<li>
<p>exp</p>
<ul>
<li>
<pre><code class="language-assembly">;-========movsb=====
mov cx,16
rep movsb
;循环16次 每次执行完后 si di ++
</code></pre>
</li>
<li>
<pre><code class="language-assembly">;========movsw
mov cx,16
rep movsw
;循环16次每次 执行完 si,di --
</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>cld -&gt; df==0<strong>++</strong></p>
</li>
<li>
<p>std -&gt; df==1<strong>--</strong></p>
</li>
</ul>
</li>
<li>
<p>pushf &amp;&amp; popf</p>
<ul>
<li>使 标志位寄存器 压栈和出栈</li>
</ul>
</li>
</ul>
<h1 id="内中断">内中断</h1>
<h2 id="1产生">1.产生</h2>
<ol>
<li>除法溢出</li>
<li>单步执行</li>
<li>执行into指令</li>
<li>执行Int 指令</li>
</ol>
<h2 id="2-中断处理程序">2. 中断处理程序</h2>
<h2 id="3-中断向量表">3. 中断向量表</h2>
<ul>
<li>中断程序的入口地址</li>
<li>存放256个中断程序入口地址</li>
<li>存放在 <strong>0000:0000</strong> 到 <strong>0000:03FF</strong></li>
<li>一个表项占两个字,高-&gt;段地址<strong>CS</strong> 低-&gt;偏移地址<strong>IP</strong></li>
</ul>
<h2 id="4中断的过程">4.中断的过程</h2>
<ol>
<li>取得中断类型码N</li>
<li>pushf</li>
<li>TF=0,IF=0</li>
<li>push CS</li>
<li>push IP</li>
<li>
<p></p><div class="math display">\[(IP)=(N*4),CS=(N*4)+2
\]</div><p></p></li>
<li>开始执行中断程序</li>
</ol>
<h2 id="5中断处理程序和iret指令">5.中断处理程序和iret指令</h2>
<ul>
<li>中断程序写法的常规步骤
<ul>
<li>保存要用的寄存器</li>
<li>处理中断</li>
<li>回复寄存器</li>
<li>用iret指令返回 --&gt; pop ip,pop cs,pop popf(pop psw)</li>
</ul>
</li>
</ul>
<h2 id="6-除法错误中断的处理">6. 除法错误中断的处理</h2>
<pre><code>1. 出现溢出
2. 产生0号中断信息
3. 执行0号中断
4. 返回操作系统
</code></pre>
<h2 id="7-编程处理0号中断">7. 编程处理0号中断</h2>
<blockquote>
<p>分析:</p>
<ol>
<li>当发生除法溢出时,产生0号中断信息,从而引发中断过程
<ol>
<li>取得中断类型码N</li>
<li>pushf</li>
<li>TF=0,IF=0</li>
<li>push CS</li>
<li>push IP</li>
<li>
<p></p><div class="math display">\[(IP)=(N*4),CS=(N*4)+2
\]</div><p></p></li>
</ol>
</li>
<li>发生0号中断时,Cpu转去执行中断处理程序
<ol>
<li>相关处理</li>
<li>向显示缓冲区送字符串</li>
<li>返回DOS</li>
<li><mark>do0</mark></li>
</ol>
</li>
<li>do0的程序应该放在那里
<ol>
<li>放在0号中断的向量表中0000:0200-0000:02FF</li>
</ol>
</li>
<li>中断程序的入口地址放在那里
<ol>
<li>cs:0000:0002,ip:0000:0000</li>
</ol>
</li>
</ol>
<p>总结</p>
<ol>
<li>编写中断处理程序do0</li>
<li>将do0送入0000:0200</li>
<li>将do0的入口地址送到存储在中断向量表0号表项中</li>
</ol>
</blockquote>
<pre><code class="language-assembly">assume cs:code

code segment

start:        do0安装程序
                设置中断向量表
                mov ax,4c00h
                int 21h
do0:        显示字符串“overflow”
                mov ax,4c00h
                int 21h

code ends
end start
</code></pre>
<h1 id="端口">端口</h1>
<hr>
<h2 id="1-端口读写指令">1. 端口读写指令</h2>
<hr>
<ul>
<li>in</li>
<li>out</li>
</ul>
<blockquote>
<p>访问端口</p>
</blockquote>
<pre><code class="language-assembly">in al , 60h;把60h中的数据读入al中
;1.cpu 通过地址线 将地址信息 60h 发出
;2.cpu 通过控制总线发出读命令 选择端口所在的芯片 并通知他 要从中读取数据
;3.端口所在的芯片 将60h端口中的数据通过数据线送入cpu
</code></pre>
<h2 id="2cmos-ram">2.CMOS RAM</h2>
<hr>
<ul>
<li>地址端口<mark>70h</mark></li>
<li>数据端口 <mark>71h</mark></li>
</ul>
<h2 id="3shlshr">3.shl,shr</h2>
<hr>
<blockquote>
<p>移位指令</p>
</blockquote>
<p><strong>左移</strong>--&gt;*2</p>
<p><strong>右移</strong>–&gt; \2</p><br><br>
来源:https://www.cnblogs.com/bgst007/p/12240237.html
頁: [1]
查看完整版本: 汇编语言学习