最近学了几天汇编 觉得需要停下来总结梳理一下自己所学
提一下 我用的教材是王爽的《汇编语言》
我认为这本书写的非常非常非常好 非常适合自学
而且很重要的一点是 这本《汇编语言》自带论坛:http://www1.asmedu.net:8086/bbs/forum.jsp
里面所有的题目都有讨论 遇到不懂的可以看看别人的讨论 里面有很多大神 看了之后一定会收获颇丰的
首先我们操作的都是内存中的单元与寄存器 那么我们先来看一下内存
内存被分为若干个单元,每个单元从0开始编号,每个单元可存储8个二进制位,即一个字节
进制的换算如下:
一个字=两个字节=两个存储单元=4个十六进制数=16位
范围为0000-FFFF
内存地址空间分为ROM与RAM
如下图所示
顾名思义
RAM Ramdom Access Memory 随机访问存储器 是可以访问且改写的一段内存空间
ROM Read Only Memory 只读存储器 是一段可以访问但是不可改写的存储空间
寄存器
8086cpu共有14个寄存器 每个寄存器都是16位的
其中AX(accumulate register)
BX(based register)
CX(count register)
DX(data register)
被称为通用寄存器 这四个寄存器都可以分为低八位与高八位 目的之一是为了与上一代CPU中的八位寄存器相兼容
注意这条指令:
ADD AL,0FFFFH
在汇编中 如果十六进制数的最高位是字母,那么要在前面加上一个0
在这个例子中,假如AL中的值不是0,那么相加后AL中的值将会产生进位,进位后的值不会进入AH中而是被丢弃
由于8086有20位地址总线,所以它的寻址能力达到了2的20次方也就是1MB
但是8086的寄存器只有16位,无法找到大于FFFF的地址,所以计算机使用的是 段地址+偏移地址的表示方法
比如指令的表示方式是CS:IP CS是代码寄存器 IP是指令指针寄存器 二者组合起来指令的实际地址是
ADDRESS=CS*16+IP
公式为 物理地址=段地址*16+偏移地址
8086共有4个段寄存器:CS DS SS ES
先说CS (code segment)
CS是代码段寄存器 跟CS连用的是IP寄存器(instructor point),即指令指针寄存器 CPU通过CS:IP来寻找要执行的指令
现在学到的更改方法有
1.用R指令修改
2.通过寄存器间接修改
比如:mov ax,2000h
mov cs,ax
3.通过jmp指令来实现跳转
使用方法 jmp 段地址:偏移地址
或者 jmp 某一合法寄存器 该操作相当于 仅仅修改IP的值为某一个合法寄存器的中的值
再说DS(data segment)
DS是数据段寄存器
在这里我们假设DS=2000H
我们可以在debug中用 MOV AL,[0]来把2000H:0中的数取出并放入AL寄存器中
注意:1.一个内存单元是8位,一个寄存器是16位,所以我们一定要用寄存器的低八位或者高八位来接收一个内存单元中的值,不然的话系统会自动填入该内存单元以及高地址方向相邻的内存单元来把ax填满
2.在debug中与在汇编编译器MASM中,针对某几段代码来说,同一段代码的含义是不一样的。
比如mov ax,[0]在debug中会将2000:0处的数据送入ax,而在汇编编译器MASM中,则是将数字0送入ax中
DS和CS一样 无法直接用mov指令对其赋值,只能通过寄存器间接赋值
接下来是SS(stack segment)
SS是段寄存器,和CS一样,它也有一个寄存器来配合使用,这个寄存器名叫SP(stack point),即堆栈指针寄存器
需要注意的是,任意时刻SS:SP指向栈顶元素
说到栈就不得不说说栈的两个操作出栈与入栈(PUSH AND POP) 笔记如下:
——————————PUSH——————————
格式:PUSH SRC
操作:SP<-(SP)-2 :栈顶指针-2 栈增加
((SP)+1,(SP))<-(SRC):将操作数放入目的地址
——————————POP——————————
格式:POP DST
操作:DST<-((SP)+1,(SP)) :将目的地址的数取出
SP<-(SP+2) :栈顶指针+2 栈减小
源操作数可以是寄存器或存储器操作数 必须以字为单位操作
重点:当栈减小后,减小的那一段中的地址里的内容仍不改变,只有当新的数据写进去时才会改变(被抹掉)。
最后是ES(extra segment)
很遗憾的是ES我还没有怎么接触,所以暂时不说
讲一个书上的简单例子:assume cs:codesg
codesg segment
mov ax,0123h
mov bx,0456h
add ax,bx
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
其中出现了三种伪指令——在汇编语言中,包含两种指令,一种是汇编指令,一种是伪指令。汇编语言是有对应的机器码的指令,可以编译为机器指令,而伪指令没有对应的机器指令,不被CPU执行而是由编译器来执行
assume cs:codesg
codesg segment
mov ax,0123h
mov bx,0456h
add ax,bx
add ax,ax
mov ax,4c00h
int 21h
codesg ends
end
伪指令1:XXX segment
…………
XXX ends
segment和ends对应使用 用来标识一个段
2:end
end是一个汇编程序结束的标记
3:assume
这条伪指令的含义是“假设”。它假设某一段寄存器和程序中的某一个segment...ends相关联
mov ax,4c00h
int 21h
这两条指令所实现的功能就是程序返回
最后说一下很重要的一点:
内存中充斥着各种0和1的组合,对cpu来说,它们都是一样的
但是在我们看来却有代码、数据之分,这完全取决于我们怎么定义那一段存储单元中的二进制信息,
我们是用各种寄存器来定义存储单元的
比如CS所指向的就是代码段
SS指向的就是栈端
而DS指向的就是数据段
仅此而已
暂时先说这么多 写完这篇之后又要开始新的学习了