汇编学习笔记

参考地址:https://www.cnblogs.com/fanjie/p/11145191.html

计算机的总线分为三种
 *地址总线:主要负责内存的寻址,每个cpu都存在多个内存总线,每个总线都只能传递0或者1,那么地址总线的组合就可以传递一个二进制码, 
 如果一个cpu存在n个地址总线,它最多能访问2^n方个地址码,那此计算机的最大可用内存也就只能是 2^n 字节。可使用内存的大小受此限制
 
 *数据总线:负责cpu和其他组件的数据传递,原理和地址总线一样,如果数据总线个数为8,每次就能传递1字节数据
 
 *控制总线:负责cpu对其他组件的控制,控制总线是一系列总线的统称,cpu有很多控制总线,每个控制总线斗代表一种基础控制指令,
 比如读数据、写数据,指令的组合使用可以完成一些复杂控制

3、存储器基本知识
1)存储器是一个统称,磁盘、内存、寄存器都是存储器,这里主要介绍内存

2)CPU进行数据计算的直接数据来源是寄存器,而寄存器的数据来源是内存了。
cpu需要计算时就将数读取到寄存器,然后从寄存器再获取到数据进真正的计算。

3)cpu想要使用数据首先必须要找到数据,内存就好象存储数据的小房间,每个房间都有一个独一无二的门牌号,这个门牌号就是内存的物理地址。
cpu要进行数据读写就必须给内存提供一个物理地址,告诉内存需要哪块数据或者数据要存储在哪块内存,这就是寻址。

4)cpu从内存读写数据分为三步 (以数据读取举例)
向内存发出一个内存区编号 > 发出指令告知内存需要读取这个编号的内容 > 内存将数据发送给cpu

5)内存其实也是多种存储器的统称,这些存储器包括主存储器,RAM存储器,ROM存储器,显卡存储器,网卡存储器等等,
这些存储器都是独立的设备,但是它们都和总线相连,于是CPU在逻辑上把它们当作一个内存,用地址空间加以区分,每个存储器占用特殊的一段地址空间

4、段和栈
1)我们在编程时经常会听到数据段、代码段、堆、栈等概念,这些概念都是方便内存管理的,对于计算机来说并没有这么复杂的概念,
cpu只知道存储空间,一些高级的抽象概念只不过是人们为了内存管理方便,把某些区域的内存规定为某类数据的专门存储地。
换句话说你可以规定任意内存作为专门存储源代码的地方,这块内存就是代码段

2)计算机中有一个基础的概念,栈。栈是一种数据结构,特点是后进先出,市面上集合所有的cpu都通过某种方式实现了这种数据结构。
cpu只有存储空间的概念, 自然不会天然的存在这种复杂的数据结构,栈的本质还是一段存储空间,只不过计算机通过某种方式保证,
后进入这段空间的数据先出去,先进入这段空间的数据后出去。只要能实现这个特点,就能说这是一个栈

3)计算机实现栈结构的方式也比较简单,使用一个寄存器保存栈顶的物理地址,在存取数据时更新此寄存器的数据,
保证这个寄存器的物理地址时刻指向栈顶,虽然cpu能时刻记录栈顶元素的位置,但是的它并不记录栈的大小, 也就是说你可以一直向栈里面压入元素,
就很可能造成栈越界,所以使用栈的时候,栈越界是必须要考虑的 


寄存器分类与用途介绍
每种CPU 的寄存器数量和用途都是不同,8086cpu含有14个寄存器 
ax | bx | cx | dx | ds | ss | cs | es |  sp | bp | si | di | ip | psw,下面介绍这些寄存器的用途

1、被用来存放一般性数据的寄存器被称为数据寄存器:ax | bx | cx | dx。
8086cpu寄存器都是16位的,而上一代寄存器都是8位的,为了向下兼容,这四个16位通用寄存器都可以被分成两个独立的8位寄存器使用,
高8位用H表示,低8位用L表示。如AX 可以被分为 AH,AL。数据寄存器没有特殊用途,一般就是存取数据,或者作为数据中转站


2、存储段地址的寄存器被称为段寄存器:cs | ds | ss | es ,
8086cpu寻址是依靠段地址加偏移地址的,以上的四个寄存器就是保存段地址,一般使用一个类型段寄存器保存一种数据的段地址,
比如cs段寄存器专门用于保存代码段,ds用于保存数据段,ss保存栈段, 但是这并不是强制的

cs(Code Segment): 代码段寄存器,cs 是8086cpu中非常重要的寄存器,
它和ip寄存器(指令指针寄存器,保存偏移地址)组合形成代码段物理地址,指示cpu将要运行的下一句代码的物理地址。

ds(Data Segment):数据段寄存器。汇编中进场需要将内存中的数据移动到寄存器计算,如mov  ax, [0] ,
这个命令是将偏移地址为0 的内存单元的数据移动至ax,我们知道一个单独的便宜地址是无法定位物理地址的,那么这个指令是不是错了呢。
并不是, cpu默认将ds寄存器内的数据当做段地址,所以要使用上面这个指令一般还会加上 mov  ds,xxx ,初始化ds的值

ss(Stack Segment):栈段寄存器。cpu中栈的实现就是依靠寄存器保存栈顶元素的物理地址,当栈数据更新时,该寄存器的值也同步更新,
这个寄存器就是ss,与之配合的保存偏移地址的寄存器就是sp和bp,ss:sp需要时刻指向栈顶元素,不可更改,那我们想要访问栈中的其他元素怎么办呢,
将sp的地址传递给bp,由 ss:bp 去寻找元素

es(Extra  Segment):  扩展段寄存器,我们寻址是必须使用段急寄存器的,但是段寄存器数量有限,可能在有些程序中会不够用,此时就可以使用es寄存器


3、变址寄存器:si  | di。si是源变址寄存器,di是目的变址寄存器,常用于串指令操作,定位串的原始位置和目标位置 。
比如将一个字符串从一个内存地址拷贝到另一个内存地址,可以使用ds:si 记录此字符串原来的地址, ds:di 记录数据将要被拷贝到的目标地。
除了这种单独的使用方式,si | di还可以和bx , bp 结合使用用于寻址。形如 mov ax, [bx + si] ,这里 [bx + si] 代表偏移地址,其值等于bx内的数据 +  si内的数据,
它的默认段地址在ds中。当si | di 与bp集合使用,段地址默认在es中


4、最特殊的寄存器标志寄存器:psw。标志寄存器名副其实, 此寄存器不像其他寄存器一样存储一个数据,
它是按位起作用的,也就是说此寄存器的每一位都含有特殊的含义的,8086cpu标志寄存器有16位,按理说它可以标示16个特殊的含义,事实却不是如此,
它只使用了0,2,4,6,7,8,9,10,119个位,其他的位没有意义,下面讲每一个位的含义

ZF标志:位于第6位,与计算指令相关,如果指令计算结果为0,ZF = 1,计算结果不为0,结果为0
PF标志:位于第2,奇偶标志位,奇偶标志位,记录相关指令执行结束后,其结果的二进制表示中1的个数是否为偶数,为偶数 pf =1,否则 pf = 0
SF标志:位于第7,符号标志位,记录相关指令结束后结果是否为负数,结果为负,sf=1,否则,sf=0
OF标志:位于第11,计算溢出标志位,记录相关指令结束后,结果是否发生了溢出,发生溢出,of=1,否则of=0


编程

1、基本指令介绍

汇编语言简单来说就是用一些单词指令代替机器指令,运行时由翻译软件将单词翻译成机器指令,所以每个机器指令在汇编中都有对应的汇编指令,
类似获取数据,加减乘除。当然,汇编语言锁含有的指令比机器指令多很多,主要分为三种

1)汇编指令:机器码的助记码,每个有对应的机器码
2)伪指令:用于编译器操作的辅助指令,没有对应机器码
3)符号体系:基本运算符号,供编译器使用,没有对应机器码

如下是一个最简单的汇编代码,中间是常用指令的介绍, 其他的就是一个最简单的汇编程序的基本结构:

assume cs:code ;将cs寄存器和代码段关联(会使用就好,不必深究)

code segment ;声明一个段(类似c语言的一个函数名加左括号)
start: ;设置程序开始位置
; --------------------- 代码编写开始 -----------------------

;数据定义
db 0,0,0,0 ;以字节方式定义数据
dw 0,0,0,0 ;以字符方式定义数据
dd 0,0,0,0 ;以双字符方式定义数据
db 100 dup(0) ;直接定义100个值为0的字节型数据
db 100 dup('a') ;直接定义100个值为 'a' 的字节型数据
db 100 dup('ab') ;直接定义100个值为 'a' 的字节型数据
db 100 dup('ab',1) ;直接定义100个值为 'a' 的字节型数据

;数据的移动
mov ax,1111B ;将二进制数到寄存器ax
mov ax,1 ;将十进制数移动到寄存器ax
mov ax,1111H ;将十六进制数移动到寄存器ax
mov ax,'a' ;字符写法
mov ax,bx ;将bx中的数据移动到ax
mov ax,[0] ;(段地址为ds,偏移地址为0) 地址处的数据移动到ax
mov ax,[bx] ;(段地址为ds,偏移地址为bx寄存器中的内容) 处的数据移动到ax
mov ax,[bx+1] ;(段地址为ds,偏移地址为bx寄存器中的内容 + 1) 处的数据移动到ax
mov ax,[bx+si+10*2] ;(段地址为ds,偏移地址为bx寄存器中的内容 + si 寄存器的内容 + 1)处的数据移动到ax
;加减乘除
add ax,1 ;ax自增 1 ,相当于 ax = ax + 1
add ax,bx ;ax自增bx ,相当于 ax = ax + bx
sub ax,1 ;ax自减 1 ,相当于 ax = ax - 1
sub ax,bx ;ax自减bx ,相当于 ax = ax - bx
inc ax ;ax自增 1 ,相当于 ax = ax + 1
dec ax ;ax自减 1 ,相当于 ax = ax - 1
;乘法规则:两个乘数的位数要么都是8位要么都是16.8位乘法,一个乘数默认放在ah,结果放在ax中;16位乘法,一个乘数默认放在ax中,结果的高位放在dx,低位放在ax
mul bl ;8位乘法,相当于 ah * bl 
mul byte ptr ds:[0] ;8位乘法,byte ptr表示取一个字节的数据作为乘数
mul bx ;16位乘法,相当于 ax * bx
mul word ptr ds:[0] ;16位乘法,word ptr表示取一个字符的数据作为乘数
;除法规则:被除数默认放在ax.除数为8位,al存储商,ah存储余数;16位除法,ax存储商,bx存储余数
div bl ;8位除法,相当于 ah * bl 
div byte ptr ds:[0] ;8位除法,byte ptr表示取一个字节的数据作为除数
div bx ;16位除法,相当于 ax * bx
div word ptr ds:[0] ;16位除法,word ptr表示取一个字符的数据作为除数

;|,将两个值的二进制数进行与或操作
and al,11H ;将al和十六进制数11H与操作,结果保存在al
and al,ah ;将al和ah与操作,结果保存在al
or al,11H ;或的规则和与规则一致
or al,ah

;转移指令,可以修改寄存器cs和ip的指令被称为转移指令
jmp short 标号 ;段内短转移,cs不变,ip改变, ip的变化范围为 -128 - 127
jmp near ptr 标号 ;段内近转移,cs不变,ip改变, ip的变化范围为 -32768 - 32767
jmp far ptr 标号 ;段间转移,cs变化
jmp word ptr 内存单元地址 ;以内存中存储的值作为转移的偏移地址
jmp dword ptr 内存单元地址 ;以内存中存储的值作为转移的偏移地址
jcxz ;条件转移,当cx=0时ip值变化
ret ;使用栈中的数据修改ip内容实现近转移,相当于:ip = ss*16+sp ;sp=sp+2
retf ;使用栈中的数据修改cs和ip内容实现远转移,相当于:ip=ss*16+sp; sp=sp+2; cs=ss*16+sp; sp=sp+2
call             ;将当前指令压如栈中,然后转移,不能实现短转移

; --------------------- 代码编写结束 ------------------------
code ends ;代声明码段结束(类似c函数的右括号)
end ;整个程序结束

 
 2、规结构化编程以及特殊关键字介绍

assume ds:data,ss:stack,cs:code                       ;把某个段寄存器与特定的段关联,表明这个寄存器专门用于保存一种特定的数据

;定义数据段
data segment
    db 100,dup(0)
data ends

;定义栈段
stack segment
    db 100,dup(0)   
stack ends
;注意:无论是数据段还是栈段,本质都是计算机为程序分配的一块内存,本程序中我们并没有指定这块内存在什么位置,操作系统在加载程序的时候会为程序自动的分配一块空间
;一般操作系统分配的这块内存空间以 ss:0 为起始位置,但是我们在程序中想要获取这个位置的话不需要使用ss寄存器的形式,直接使用 mov ax,data 就可以获取到数据的段地址
;至于数据的偏移地址是需要我们根据实际情况计算的

;定义代码段
code segment
start:        mov ax,offset  start                    ;offset 用于获取标号相对寄存器ip保存值的偏移地址,相当于 :mov ax,0
second:       mov ax,offset  second                   ;相当于mov ax,3 (前一个指令占用三个字节)
              
              mov cx,10
s:            add ax,2                                ;loop 用于循环,寄存器cx保存的数字是循环次数,每循环一次,cx减1,,cx等于0时跳出循环
              loop s                                  ;loop 跳转到标号s 处执行程序

              jmp short s
              jmp  a 
              

code ends

end start

参考地址:https://www.cnblogs.com/fanjie/p/11145191.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值