汇编学习

汇编语言

机器语言是机器指令的集合

机器指令是一台机器可以正确执行的命令

机器指令有一串二进制表示


汇编语言的主题是汇编指令

汇编指令和机器指令的差别在于指令的表示方法上:

汇编指令是机器指令便于记忆的书写格式

汇编指令是机器指令的助记符

MOVAX,BX 将寄存器BX的内容送到AX中

寄存器:CPU中可以存储数据的期间,一个cpu中有多个寄存器


流程:汇编指令---编译器---机器码----计算机

汇编指令是机器码的助记符

伪指令--由编译器执行


CPU是计算机的核心部件,他控制整个计算机的运作并进行运算,要想让一个cpu工作,就必须向他提供指令和数据

指令和数据在存储器中存放,离开了内存,性能再好的cpu也无法工作


指令和数据的表示:

计算机中的数据和指令,存储在内存或磁盘上

数据和指令,都是二进制信息

问题:二进制信息1000001010100是数据,还是指令

二进制是指令还是数据有cpu决定:

当二进制信息是数据是-->被转换成了十六进制

当二进制信息是指令时-->被转换成了汇编代码


数据的表示:

二进制:B 十六进制:H 八进制:O 十进制: D


计算机中的存储单元:

存储器被划分为诺干个存储单元,背个存储单元从0开始顺序编号

总线:数据总线(cpu玉内存或其他器件之间的数据传送是通过数据总线来进行的,数据总线的宽度决定了cpu和外界的数据传送速度),地址总线(cpu通过地址总线来指定存储单元),控制总线(cpu通过控制总线对外部器件进行控制)


CPU要想进行数据的读写,必须和外部器件进行三类信息的交互:

存储单元的地址(地址信息);器件的选择,读或写命令(控制信息);读或写的数据(数据信息)

汇编指令 MOV AL,[3]

首先地址线寻址,找到内存单元3,之后控制线发出控制信息读,然后数据线将3内存单元的信息存放到了AL中


什么是内存地址空间:

CPU的总线宽度为N,寻址空间为2的n,例如8086CPU的地址总线宽度为20,那么可以寻址1mb个内存单元。其内存地址空间为1MB

RAM:能读能写,掉电之后清除

ROM:只能读(BIOS)

image-20231017204621466

将各类存储器看做一个裸机存储器--统一编址

所有的物理存储器被看做一个由诺干个存储单元组成的逻辑存储器

每个物理存储器在这个逻辑存储器中占-you一个地址段,即一段地址空间

CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据

8086PC机为例

image-20231017205003628

访问寄存器和内存=

cpu的组成:

运算器进行信息处理;

寄存器进行信息存储

控制器协调各种器件进行工作

内部总线时间cpu内各个器件之间的联系


寄存器是cpu内部信息存储单元

8086cpu有14个寄存器

通用寄存器:AX,BX,CX,DX

变址寄存器:SI,DI

指针寄存器:SP,BP

指令指针寄存器:IP

段寄存器:CS,SS,DS,ES

标志寄存器:PSW

共性:所有寄存器都是16位的可以存储两字节的数据

一个寄存器存储一个16为的数据

最大值FFFFH


问题:8086上一代cpu中的寄存器都是8位的,如何保证程序的兼容性。

方案:通用寄存器均可分为两个独立的8为寄存器使用

细分为:AX分为:AH和AL


mov和add指令:

mov ax,18 将18送入AX

mov ah,78将78送入ah中

add ax,8 将寄存器ax中的数值加上8

mov ax,bx 将寄存器bx中的数据送入寄存器ax中

add ax,bx 将ax,bx中的内容相加,结果存在ax中

在进行指令相加时溢出为会被丢掉


CPU访问内存单元时要给出内存单元地址

所有的内存单元构成的存储空间是一个一维线性空间

每一个内存单元在这个空间中都有唯一的地址,这个唯一的地址值称为物理地址

问题:实际上8086有20为地址总线,可传送20为地址,寻址能力为1m,但8086是16位结构的cpu 运算器一次最多可以处理16位的数据,寄存器的最大宽度为16位,那么8086如何处理在寻址空间上的这个矛盾?

方法:

用两个16位地址段,偏移地址合成一个20位的物理地址

物理地址=段地址x16+偏移地址

image-20231017214737550

image-20231017215013927

内存并没有分段,段的划分来自cpu

image-20231017220011116

段地址很重要--用专门低寄存器放段地址

4个段寄存器:

CS -代码段寄存器

DS -数据段寄存器

SS -栈寄存器

ES-附加段寄存器


debug的使用

r-查看,改变cpu寄存器内容

d:查看内存中的内容

e:改变内存中的内容

u:将内存中的机器指令翻译成汇编指令

a:以汇编指令的格式在存储中写机器指令(这里我们写的是汇编指令,但是在实际的内存中,被编译成了机器码存储到了 内存中)

t:执行机器指令(执行CS:IP处的机器代码)

e 地址 数据-写入

d 地址 -查看

u 地址 -查看代码

q:退出

CS 是代码执行的段地址

IP 是代码执行的偏移地址

CS 和IP寄存器

CS:代码段寄存器

IP:指令指针寄存器

CS:IP:CPU将内存中cs:ip

指向的内容当作指令执行

CS和IP通过加法器转换成20位地址,然后定位到内存中代码存放的地方

8086PC工作过程的简要描述:

从CS:IP指向内存单元读取指令,读取的指令进入指令缓存器;

IP=IP+所读取指令的长度,从而指向下一条指令

那么,所读指令的字节数应该怎么判断呢?

汇编指令长度与寻址方式有关,规律或原则如下:

一、没有操作数的指令,指令长度为*1*个字节

二、操作数只涉及寄存器的的指令,指令长度为*2*个字节

  如:*mov bx,ax*

三、操作数涉及内存地址的指令,指令长度为*3*个字节

  如:*mov ax,ds:[bx+si+idata]*

四、操作数涉及立即数的指令,指令长度为:寄存器类型*+1*

  *8*位寄存器,寄存器类型*=1*,如:*mov al,8*;指令长度为*2*个字节

  *16*位寄存器,寄存器类型*=2*,如:*mov ax,8*;指令长度为*3*个字节

问题:内存中有数据B8 23 01 BB 03 00 89 D8 01 D8 究竟用作一般数据,还是用作指令?

cpu将CS:IP 指向的内存单元中的内容看作指令


事实:执行何处的指令,取决于CS :IP 指向的物理地址

应用:可以通过改变CS ,IP中的内容,来控制CPU要执行的目标指令

问题如何改变cs:ip的值

方法一:用指令修改

mov cs 2000h 但是这种方法是不行的

jmp转移指令

同时修改cs和ip的内容:

jmp 段地址 : 偏移地址

仅修改IP的内容:

jmp某一合法寄存器

jmp ax (类似于mov IP ax)


内存中字的存储:

对8086cpu中16位作为一个字

image-20231018220122083

解决问题:CPU从内存单元中药读取数据

CPU要读取一个内存单元的时候,必须先给出这个内存单元的地址

原理:在8086CPU中,内存地址由段地址和偏移地址组成

解决方法:DS和[address]配合

用DS寄存器存放要访问的数据的段地址,偏移地址用[...]的形式直接给出

mov bx,1000h
mov ds,bx
mov al,[0]
将10000H(1000:0)中的数据读到al中
--------------------
mov bx,1000h
mov ds,bx
mov [0],al
将al里面的数据放到[1000:0]中

要给段寄存器赋值改值的话必须通过通用寄存器去间接改变

mov bx,1000H
mov ds,bx
8086不支持将数据直接送入段寄存器中

CS是值CPU执行的当前指令的段地址,DS是数据开始的段地址

表示一个物理地址,其中段地址和偏移地址不是固定的


栈是一种只能在一端进行插入或删除操作的数据结构

栈有两个基本的操作:入栈和出栈

出栈:从栈顶取出一个元素

栈顶的元素总是最后入栈,需要出栈时,又最先被从栈中取出

栈的操作规则:LIFO 后进先出

CPU提供的栈机制:

现在的CPU中都有栈的设计

8086CPU提供相关的指令,支持用栈的方式访问内存空间

基于8086CPU的编程,可以将一段内存当作栈来使用

PUSH入栈和POP出栈指令

push ax:将ax中的数据送入栈中

pop ax:从栈顶取出数据送入ax,以字为单位对栈进行操作


cpu如何知道一段空间被当作栈使用?

cpu由两个与栈相关的寄存器:栈段寄存器ss 存放栈顶的段地址 栈顶指针寄存器SP 存放栈顶的偏移地址

任意时刻:ss:sp指向栈顶元素

cpu只是知道栈顶在何处,不知道程序安排的栈空间有多大

push ,pop 实质是内存传送指令,可以在寄存器和内存之间传送苏剧,与mov指令不同的是


汇编语言程序--->编译器----->机器码

伪指令:没有对应的机器码的指令,最终不被cpu所执行

伪指令是由编译器来执行的指令,编译器根据伪指令来进行相关的编译工作

汇编指令:对应由机器码的指令,可以被编译为机器指令,最终被cpu执行


段定义:

一个汇编程序是由多个段组成的,这些段被用来存放代码,数据或者当作栈空间来使用

一个有意义的汇编程序中至少要有一个段,这个段用来存放代码

定义程序中的段:每个段都需要有段名

段名 segment --段的开始

......

段名 ends ---段的结束

assume(假设)

含义是假设某一段寄存器和程序中的某一个用segment ---ends定义的段相关联

assume cs:codesg指cs寄存器与codesg关联,将定义的codesg当作程序的代码段使用

inc:

loop指令:实现循环(计数型循环)

指令的格式:loop 标号

cpu执行loop指令时要进行的操作:

1.(cx)=(cx)-1

2.判断cx中的值:不为零则转至标号出执行程序,如果为零则向下执行

要求:cx中要提前存放循环次数,应为cx影响这loop指令的执行结果

要定义一个标号


段前缀的使用

inc 连续累加

mov bx,0
inc bx //这是bx就是1

accume cs:code
code segment
mov ax,0ffffh
mov ds,ax ##设置数据段地址
mov bx,0 ##初始化bx寄存器,这个寄存器用于存放地址单元块的标号
mov dx,0 ##初始化bx寄存器,这个寄存器用于存放各个地址单元的相加值
assume cs:code
code segment 
  

编程计算一下8个数据的和,结果存在ax寄存器中:

0123h,0456h,0789h,0abch,0defh,0fdeh,0987h,0387h

解决方案:

assume cs:code
code segment
 dw 0123h,0456h,0789h,0abch,0defh,0fdeh,0987h,0387h
start: mov bx,0
 mov ax,0
 mov cx,0
s: add ax,cs:[bx]
 add bx,2
 loop s
 mov ax,4c00h
 int 21h
 code ends
 end start
 效果:程序加载后cs:ip指向程序的入口
posted @ 2023-11-03 00:17  kill比尔  阅读(40)  评论(0)    收藏  举报