【问题】汇编笔记原来的基础上加了点
学汇编
这篇文章用记录王爽版8086cpu的学历程
两个重要的知识点学汇编语言,首先必须了解两个知识点寄存器和内存模型。
先看寄存器。CPU 本身只负责运算,不负责储存数据。数据一般都储存在内存之,CPU 要用的时候就去内存读写数据。但是,CPU 的运算速度远高于内存的读写速度,为了避免被拖慢,CPU 都自带一级缓存和二级缓存。基本上,CPU 缓存可以看作是读写速度较快的内存。
但是,CPU 缓存还是不够快,另外数据在缓存里面的地址是不固定的,CPU 每次读写都要寻址也会拖慢速度。因此,除了缓存之外,CPU 还自带了寄存器register,用储存最常用的数据。也就是说,那些最频繁读写的数据比如循环变量,都会放在寄存器里面,CPU 优先读写寄存器,再由寄存器跟内存交换数据。
寄存器不依靠地址区分数据,而依靠名称。每一个寄存器都有自己的名称,我们告诉 CPU 去具体的哪一个寄存器拿数据,这样的速度是最快的。有人比喻寄存器是 CPU 的零级缓存。
王爽8086CPU的需要记住寄存器
指令伪指令没有对应的机器码,由编译器执行,计算机并不执行。汇编指令机器码的记助符,有对应的机器码。
CPU要工作必须向它提供指令和数据,指令和数据在存储器存放,也就是我们时说的内存,CPU不能使用磁盘上的数据。
CPU要从内存读数据,首先要指定存储单元的地址。
存储器被划分为若干个存储单元从0开始顺序编码,例如一个存储器有128个存储单元,它可以存储128个Byte,编码从0127。
最信息单位bit比特,也就是一个二进制位。一个存储单元可以存储8个bit,即8位二进制数。8个bit组成一个Byte,也就是一个字节。微型机存储器的存储单元可以存储一个Byte,即8个二进制位。1KB1024B1MB1024KB1GB1024MB1TB1024GB
地址总线上能传送多少个不同的信息,CPU就可以对多少个存储单元进行寻址。一根导线可以传送的稳定状态只有1高电和0低电两种,10根导线可以传送10位二进制数据,而10位二进制数可以表示2的10次方个不同的数据。一个CPU有N根地址线,则可以说这个CPU的地址总线的宽度为N,这样的CPU最多可以寻找2的N次方个存储单元。测验题
例,1个CPU的寻址能力为8KB,那么它的地址总线的宽度为13。 解析1KB1024B,8KB1024B 8 , N13
例,80808088的地址总线宽度分别位16根20根24根32根, 则他们的寻址能力分别为64KB1MB4MB4GB。 解析一个内存单 元1Byte 8根数据总线一次可以传送8位二进制数据即一个字节。 例,808080888086的数据总线宽度分别为8根8根16根16根32根,则他们一次可以传送的数据为1B1B2B2B4B.
例,从内存读取1024字节的数据,8086至少读512次,至少读256次。
解析8086的数据总线宽度为16根即一次传送的数据为2B 1024B2B512,同理1024B4B256。
在存储器指令和数据没有任何区别,都是二进制信息。就像棋盒的黑白棋子,只有在棋盘展开对弈时才有意义,在棋盒是没有实际意义的地址总线的宽度决定了CPU的寻址能力;数据总线的宽度决定了CPU与其他器件进行数据传送时的一次数据传送量;控制总线的宽度决定了CPU对系统其他器件的控制能力。
内存地址空间的大受CPU地址总线宽度的限制,8086CPU的地址总线宽度为20,可以传送 个不同的地址信息,即可以定位 个内存单元,则8086PC的内存地址空间大为1MB。
mov指令将逗号右边的给逗号左边的要保证寄存器与寄存器之间 数据与寄存器之间 的位数一致性寄存器是相互独立的, al就是al ah就是ah 不会相互影响16位寄存器进行16位运算 保存16位数据 8位寄存器进行8位运算保存8位数据
指令是有长度的,一条指令可以有多个字节组成
指令的执行过程cpu从csip 所指向的内存单元读取指令,存放到指令存储器ipip所读指令的长度,从而指向下一条指令执行指令缓存器的内容,回到第一步
在进行数据传送或运算时,要注意指令的两个操作对象的为啥应当是一致的,如下面的指令都是错误的mov ax,bl 在8位寄存器和16位寄存器之间传送数据mov bh,ax 在16位寄存器和8位寄存器之间传送数据mov al,2000 8位寄存器最大可存放值位255的数据add al,100H 将一个高于8位的数据加到一个8位寄存器 CPU访问内存单元时,要给出内存单元的地址,所有的内存单元构成的存储空间是一个一维的线性空间,每个内存单元在这个空间都有唯一的地址,我们将这个唯一的地址称为物理地址。CPU通过地址总线送入存储器的,必须是一个内存单元的物理地址。 8086CPU有20位地址总线,可以传送20位地址,达到1MB的寻址能力,而8086CPU又是16位结构,在内部一次性处理传输暂时存储的地址位16位。8086CPU采用一种在内部用两个16位地址段地址偏移地址合成的方法形成一个20位的物理地址。
物理地址段地址SAx16偏移地址EA 或 物理地址基础地址偏移地址 段地址x16更有一种说法是左移4位指二进制位。一个数据的二进制形式左移1位,相当于该数据乘以2;左移N位,相当于该数据乘以2的N次方。 段地址x16必然是16的倍数,一个段的起始地址一定是16的倍数;偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的长度最大为 64KB。CPU可以用不同的段地址和偏移地址形成同一个物理地址。偏移地址16位,变化范围为0FFFFH,仅用偏移地址寻址最多可寻 64KB 个内存单元。
例给定段地址为0001H,仅通过变化偏移地址寻址,CPU 的寻址范围为0010H到1000FH。
解析 物理地址SA 16EA,EA的变化范围为0H FFFFH ; 物理地址范围为SA 160H SA 16FFFFH, 现在SA0001H,那么寻址范围为 0001H160H 0001 H 16FFFFH0010H1000FH
2.有一数据存放在内存H单元,现给定段地址为SA,若想用偏移地址寻到此单元。则SA应满足的条件是最为1001H ,最大为2000H。当段地址给定为1001H 以下和2000H 以上, CPU无论怎么变化偏移地址都无法寻到H单元。
解析 物理地址 SA 16EA;H SA 16EA; SA H EA 162000HEA16;EA取最大值时, SA2000HFFFFH161001H;SA为最值,EA取最值时,SA2000H0H162000H,SA为最大
8086 cpu 设计者给了它20根地址线 表示范围 0FFFFFH地址线的数量决定了cpu的寻址能力地址加法器决定地址的计算方式
段地址 1610H偏移地址 物理地址
因为8086cpu有20根地址线,16位寄存器无法表示,所以采取这样的方式 段地址 16 基础地址 ,基础地址偏移地址物理地址
冒号前段地址 ,冒号后偏移地址
debug
U指令 将某个内存地址 开始的字节 全部当做指令
D 指令 将某个内存开始的字节 全部当成数据
CPU是怎样区分指令和数据的?
8086cpu
在任意时刻,cpu将cs ip所指向的内容全部当成指令执行, 在内存指令和数据是没有任何区别的,都是二进制信息,cpu只有在工作的时候才将有的信息当做指令 有的信息当做数据,cpu根据什么将内存的信息当做指令的话,cpu将cs, ip 指向的内存单元的内容当做指令
指令和数据在内存有区别吗?
是没有区别的 在cpu的cs段地址寄存器和 ip这个偏移地址寄存器 组合的时候从读取内容当做指令执行 csip 决定了cpu从哪里开始读取指令
指令是有长度的,一条指令可以由多个字节构成
指令的执行过程cpu从csip 所指向的内存单元读取指令,存放到指令缓存器ipip所读指令的长度,从而指向下一条指令执行指令缓存器的内容,回到步骤一
明白ip寄存器和指令的关系
汇编指令 jmp jump的简写
这是一条转移指令,可以修改cs和ip这2个寄存器
两种写法 Jmp 20000 ,Jmp寄存器
例题假设cs2000H ,ip0000 写出下列指令的执行过程
Debug 调试工具
一个字型数据 存放在内存 可以有2个连续的地址的内存单元组成高地址内存单元存放 字型数据的高位字节低地址 内存单元存放 字型数据的地位字节
例 0 20H
1 4EH
2 12H
3 00H 问题
CPU 通过内存地址去访问内存
DS 段地址寄存器 访问数据用的
mov al,ds0mov移动指令 逗号左边是CPU的al寄存器,逗号右边是内存地址,0是偏移地址,表示得到里面的内容.
结字型数据和字节型数据 在内存的存放字型数据在内存存储时,需要2个地址连续的内存单元存放,高位字节存放在高地址,低位字节存放在低地址CS 和指令有关DS 段地址寄存器 数据段地址寄存器 和数据有关CSIP 指令从哪里DS 数据从哪里修改寄存器的内容 去控制cpu 进而控制计算机
在8086cpu,在任意时刻将段地址寄存器ss和偏移地址寄存器sp所组合出的内存地址当做栈顶标记
我们可以 决定栈顶标记在哪里栈在哪里 箱子在哪里 栈的大箱子的大
栈的设置 起始地址 你所设定的栈的大的字节数
栈的作用临时性保存数据用栈进行数据交换保存在栈 每执行一条t指令 就会将寄存器保存到栈Call ip 保存到栈 ,为了让ret指令可以从栈拿回
我们如何让cpu按照我们的安排去访问这些内存段呢?
对于数据段说,段地址 ds段寄存器 0 1 mov add sub 指令去访问这些内存单元 那么CPU就会将我们定义的数据段的内容当做数据访问
对于代码段说,我们可以通过修改 cs,ip 这2个寄存器,去指向我们定义的代码段 这样cpu就执行我们定义的代码段的指令
对于栈段说,我们可以通过修改,ss,sp这2个寄存器去决定栈顶标记在哪里 这样CPU在执行栈的操作时,比如pop,push就会将我们定义的栈段当做栈空间使用
不管我们如何安排,cpu将内存某段内容当做指令 是因为csip 指向那里 cpu将某段内存当做栈空间是因为 sssp 指向那里
数据从哪里,临时性的数据存放到哪里去,取决于我们cpu的地址寄存器的设置 cs ip ss sp ds 寄存器
寻址方式的思维导图
子程序汇编的子程序调用对应的高级语言的部分函数调用 call 子程序的名字执行到这里,cpu 会做两件事。一是保存,二是跳转保存ip 指令指针。如果是段内跳转。会将当前的ip 偏移值压入栈。如果是段间跳转,会将cs 段寄存器的段地址,和ip 指令指针偏移值 压入栈跳转根据子程序的名字跳转到指定的位置
子程序的格式名字 pro 程序入口内容 将在这个子程序会使用到的寄存器压入栈在程序结束时要将寄存器弹出栈在程序执行结束,子程序末尾ret 表达式 段内是ret 段间是retf子程序名字 endp , 程序执行结束后,堆栈会将要入栈的cs 和ip 弹出栈。让程序返回调用处继续向下执行。 关于ret 后面的表达式会改变栈的指针,也就是在CS 和IP 都被弹出栈后表达式的值就是栈的指针SP 还要移动的字节数
关于参数使用寄存器传递在调用子程序之前先将参数压入栈
理解了汇编子程序的调用,再返回看高级语言函数的调用就不难了。在高级语言定义了函数名是函数的起始地址。所以在调用函数时,都会使用函数名,其实就是相当于跳转目的地址,在堆栈存放的是在函数调用的临时变量,存放的函数执行完之后继续执行的地址
标志寄存器