当前位置:文档之家› 汇编语言学习笔记

汇编语言学习笔记

汇编语言学习笔记《汇编语言》--王爽前言学习汇编目的:充分获得底层编程体验;深刻理解机器运行程序的机理。

原则:没有通过监测点不要向下学习;没有完成当前实验不要向下学习。

第一章基础知识有三类指令组成汇编语言:汇编指令;伪指令;其他符号。

8bit = 1byte = 一个存储单元有n根地址线,则可以寻址2的n次方个内存单元。

1.1节--1.10节小结(1)汇编指令是机器指令的助记符,同机器指令一一对应。

(2)每一种cpu都有自己的汇编指令集。

(3)cpu可以直接使用的信息在存储器中存放。

(4)在存储器中指令和数据没有任何区别,都是二进制信息。

(5)存储单元从零开始顺序编号。

(6)一个存储单元可以存储8个bit,即八位二进制数。

(7)每一个cpu芯片都有许多管脚,这些管脚和总线相连。

也可以说,这些管脚引出总线。

一个cpu可以引出的三种总线的宽度标志了这个cpu不同方面的性能。

地址总线的宽度决定了cpu的寻址能力;数据总线的宽度决定了cpu与其他器件进行数据传送时的一次数据传送量;控制总线的宽度决定了cpu对系统中其他器件的控制能力。

监测点:1KB的存储器有1024个存储单元?存储单元的编号从0到1023.内存地址空间:最终运行程序的是cpu,我们用汇编编程时,必须要从cpu的角度思考问题。

对cpu来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受cpu寻址能力的限制。

这个逻辑存储器即是我们所说的内存地址空间。

第二章寄存器(cpu的工作原理)mov ax, 2add ax, axadd ax, axadd ax, ax(1)cpu中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址;(2)段地址和偏移地址通过内部总线送人一个称为地址加法器的部件;(3)地址加法器将两个16位地址合成为一个20位的物理地址;(4)地址加法器通过内部总线将20位物理地址送人输入输出控制电路;(5)输入输出控制电路将20位物理地址送上地址总线;(6)20位物理地址被地址总线传送到存储器;段地址*16+偏移地址= 物理地址的本质含义内存并没有分段,段的划分来自cpu。

以后编程时可以根据需要,将若干地址连续的内存单元看做一个段,用段地址*16定位段的起始地址,用偏移地址定位段的内存单元。

一个段的起始地址一定是16的倍数,一个段的最大长度为64kB。

当然也没有办法定义一个起始地址不是16的倍数的段。

cpu可以用不同的段地址和偏移地址形成同一物理地址。

在8086cpu加电启动或复位后cs和ip被设置为cs = f000h,ip = ffffh,即ffff0h单元中的指令是8086pc机开机后执行的第一条指令。

(??应该是fffffh吧??)cpu将cs:ip指向的内存单元看做指令。

在cpu中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对cpu的控制。

mov指令称为传送指令,cpu中大部分寄存器的值都可以通过mov指令改变。

除了cs:ip 8086没给他这样的功能。

cs:ip可以用转移指令来改变。

jmpjmp cs:ip 用指令给出的段地址修改cs,偏移地址修改ipjmp 某一寄存器的功能为:用寄存器中的值修改ipjmp ax 含义类似于mov ip,ax段地址在8086pc机的段寄存器存放。

当8086cpu要访问内存时,由段寄存器提供内存单元的段地址。

8086cpu有四个段寄存器,其中cs用来存放指令的段地址。

cs存放指令的段地址,ip存放指令的偏移地址。

8086机中,任意时刻,cpu将cs:ip指向的内容当作指令执行。

8086cpu的工作过程:1.从cs:ip指向内存单元读取指令,读取的指令进入指令缓冲器;2.ip指向下一条指令3.执行8086提供转移指令修改cs:ip的内容debug的使用查看,修改cpu中寄存器的内容:r命令查看内存中的命令:d命令修改内存中的内容:e命令(可以写入数据,指令,在内存中,它们实际上没有区别)将内存中的命令解释为机器指令和相应的汇编指令:u命令执行cs:ip指向的内存单元处的命令:t命令以汇编指令的形式向内存中写入指令:a命令第三章寄存器(内存访问)3.1内存中字的存储高八位存放在高字节中,低八位存放在低字节中3.2DS和【address】3.3字传送3.4MOV ADD SUB3.5数据段3.6栈栈是一种具有特殊的访问方式的存储空间。

它的特殊性就在于,最后进入这个空间的数据,最先出去。

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

栈的这种操作规则被称为:lifo(last in first out,后进先出)。

cpu如何知道10000H--1000fH这段空间被当作栈使用?push pop指令在执行时必须知道哪个单元是栈顶单元,可是如何知道呢?栈顶的段地址存放在ss中,偏移地址存放在sp中。

任意时刻,ss:sp指向栈顶单元。

push和pop指令执行时,cpu从ss和sp中得到栈顶的地址。

入栈时,栈顶从高地址向低地址方向增长。

如何定义一个栈的大小?mov ax, 1000hmov ss, axmov sp, 0010h ;则栈顶为1000f 栈底为10000******************************************mov ax, 1000hmov ds, axmov ax, 2266hmov [0], ax************************mov ax,1000hmov ss, axmov sp, 0002hmov ax, 2266hpush ax栈顶的变化范围最大为:0--ffffh栈的综述(1)8086cpu提供了栈操作机制,方案如下:在ss、sp中存放栈顶的段地址和偏移地址;提供入栈和出栈指令,他们根据ss、sp指示的地址,按照栈的方式访问内存单元。

(2)push指令的执行步骤:1)sp=sp-2;2)向ss:sp指向的字单元送人数据;(3)pop指令的执行步骤:1)从ss:sp指向的字单元中读取数据;2)sp=sp+2(4)任意时刻,ss:sp指向栈顶元素。

(5)8086cpu只记录栈顶,栈空间的大小我们要自己管理。

(6)用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。

(7)push、pop指令实质上是一种内存传送指令,注意他们的灵活运用。

一个栈段最大可以设为64k段的综述我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。

这完全是我们的安排。

用一个段存放代码,即代码段用一个段存放数据,即数据段用一个段当栈,即栈段对于数据段,把段地址放在ds中,用mov,add,sub等访问内存单元的指令时,cpu就将我们定义的数据段内容当做数据来访问;对于代码段,把段地址放在cs:ip中,用mov,add,sub等访问内存单元的指令时,cpu 就将执行我们定义的代码段的指令;对于栈段,把段地址放在ss:sp中,用push pop 等访问内存单元的指令时,cpu就将其当作堆栈来访问;debug的t命令在执行修改器ss的指令时,下一条指令也紧接着被执行了。

3.7栈超界问题8086cpu不保证我们对栈的操作不会超界。

也就是说,8086cpu只知道栈顶在何处而不知道我们安排的栈空间有多大,这点就好像,cpu只知道当前要执行的指令在何处,而不知道要执行的指令有多少。

从这两点我们可以看出cpu的工作机理,它只考虑当前情况:当前的栈在何处,当前要执行的指令是哪一条。

对于超界问题我们可以做到就是小心。

第五章【bx】和loop指令我们完整的描述一个内存单元,需要两种信息:(1)内存单元的地址;(2)内存单元存放数据的类型;inc bx的含义是bx中的内容加一[bx]寄存器bx中所包含的地址中存放的内容[bx]表示一个内存单元,他的偏移地址在bx中。

loop指令执行的时候,要进行两步操作:1;(cx)=(cx)- 1;2;判断cx中的值,不为零则转至标号处执行。

“通常”我们用loop实现循环功能,cx中存放循环次数。

用cx和loop指令相配合实现循环功能的三个要点:(1)再cx中存放循环次数;(2)loop指令中的标号所标识地址要在前面;(3)要循环执行的程序段,要写在标号和loop指令的中间。

在汇编源程序中,数据不能以字母开头。

所以对于大于9fffh的数,均在前面加上0。

mov cx,11s: add ax,axloop sassume cs:codecode segment..mov ax,4c00hint 21hcode endsendffff:6单元是一个字节单元,ax是一个十六位寄存器,数据长度不一样,如何赋值?注意我们说的是“赋值”,就是说,让ax中的数据的值(数据的大小)和ffff:0006单元中的数据的值(数据的大小)相等。

八位数据01h和16位数据0001h的数据长度不一样,但他们的值是相等的。

设ffff:0006单元中的的数据是xxh,若要ax中的值和ffff:0006单元中的值相等,ax中的数据应为00xxh。

所以,若实现ffff:0006单元向ax赋值,我们应该令(ah)=0,(al)=(ffff6H).若希望程序能从cs:0012处执行,可以用g命令。

“g 0012”。

他表示程序执行到0012处。

若希望程序能跳出循环,用p命令5.4 debug和汇编编译器masm对指令的不同处理。

在汇编源程序中,mov al,[0]会被编译器解释成为:mov al,0所以要这样表达:mov bx,0mov al,[bx]或者 mov al,ds:[0]第一,我们在汇编源程序中,如果用指令访问一个内存单元,则在指令中必须用[...]来表示内存单元,如果在[]里用一个常量idata直接给出内存单元的偏移地址,就要在[]的前面显示地给出段地址所在的段寄存器。

第二,如果在[]里用寄存器,比如bx,间接给出内存单元的偏移地址,则段寄存器默认在ds中。

第六章包含多个段的程序程序取得所需段的方法有两种:一是在加载程序的时候为程序分配,再就是程序在执行的过程中向系统申请。

dw的含义是定义字型数据即define word 字型数据间以逗号隔开。

程序运行的时候cs存放代码段的段地址,所以我们可以从cs中得到它们的段地址。

dw定义的数据处于代码段的最开始,所以偏移地址为零。

dw 0123h,5604h,1234hstart :指令end start我们在程序的第一条指令的前面加了一个标号start:并在end的后面再次加入。

end除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。

在单任务系统中,可执行文件中的程序执行如下:(1)由其他的程序(debug、command或其他程序)将可执行文件中的程序加载入内存;(2)设置cs:ip指向程序的第一条要执行的指令(即程序的入口),从而使程序得以运行;(3)程序运行结束后,返回到加载者;描述信息可执行文件由描述信息和程序组成,程序来源于源程序中的汇编指令和定义的数据;描述信息则主要是编译连接程序对原程序中相关伪指令进行处理所得到的信息。

相关主题