三、寄存器:
1、内存中字的存储
已知的mov指令可完成的两种传送功能:
1)将数据之间送入寄存器中; 如:mov ax,2
2)将一个寄存器中的内容送入另一个寄存器中。 mov bx,ax
3)还有一个功能,将一个内存单元中的内容送入一个寄存器中,mov al,[0]
DS和[address]是数据的段地址,和偏移地址
mov al,[0]是从哪个内存单元送入到寄存器中呢,[0]是偏移地址,那么段地址是哪个。
执行指令时,8086CPU自动取DS中的数据为内存单元的段地址。如何用mov指令从10000H中读取数据?
1、10000H表示为1000:0(段地址:偏移地址)
2、将段地址1000H放入ds中
3、用mov al,[0] 完成传送。
如何把1000H送入ds?
8086CPU不能将数据之间送入段寄存器的操作,ds是一个段寄存器。(硬件设计的问题)
mov ds,1000H是非法的
数据->通用寄存器->段寄存器
-------------
怎样将数据从寄存器送入内存单元中。写入
mov bx,1000H 将1000H放入寄存器bx中
mov ds,bx 将bx的数据送入到ds段寄存器中,这时ds的段地址是1000H,设置ds段地址
mov ax,[0] 将[0]偏移地址送入到ax寄存器中个,
mov [0],cx 将cx的16位数据送到1000:0处;
[0],cx 这里的[0]代表的是ds:[0],
--------
字的存储(数据的存储)读取
将10000H 23;10001H 11;10002H 22 10003H 11存入到内存中;
1、使用-e 1000:0 23 11 22 11将上面的内容存放到内存中;
汇编指令使用-a 命令向1400:100地址写入以下命令
mov ax,1000H
mov ds,ax 前两条是设置读取内存单元数据的段地址
mov ax,[0] 将1000:0内存单元中的数据读入到ax寄存器中
mov bx,[2] 将1000:2内存单元中的数据送入到bx寄存中
mov cx,[1]
add bx,[1]
add cx,[2]
执行命令是从1000:0读取数据,
add cx,[2]
注:这里要清楚的意识到,指令与数据都是在内存中存放的;-a 命令是将指令存放在内存单元中,-e是将数据存放在内存单元中。如果利用指令操作内存的话,先要在指令写入到内存中,然后利用-t命令执行指令(这时要清楚指令存放的段地址:偏移地址,cs:ip地址)。在写指令时,一定是将指令存放在内存,如果指令中有ds
操作,[0],ax是将ax寄存器中的数据存放到ds:[0]的内存单元中。如果是ax,[0]是从ds:[0]内存单元中读取数据,存放到ax寄存器中。
sub是减法
---------------------
栈:是一种具有特殊的访问方式的存储空间。最后进入这个空间的数据,最先出去的。
入栈:将一个新的元素放到栈顶。
出栈:从栈顶取出一个元素。last in first out
8086可以将一段内存当作栈来使用
push ax:将寄存器ax中的数据送入栈中;
pop ax:从栈顶取出数据送入ax。
8086CPU中,有两个寄存器:
段寄存器:存放栈顶的段地址
寄存器SP:存放栈顶的偏移地址
任意时刻:SS:SP指向栈顶元素。
当执行push ax,CPU会发生:
1)、SP=SP-2;
当执行pop ax,CPU会发生:
SP = SP+2;
注:当栈为空时,栈中没有元素,也就不存在栈顶元素
--------
栈顶超界:当存储的内存超过栈存储空间。C语言是没有栈顶越界检测的,是由编译器分配的(堆是由程序员指定的),java语言是越界检测机制的。
8086CPU只知道栈顶在何处,而不知道用户知道栈的存储空间有多大。
---------
push ax,将寄存器ax中的数据放入到当前栈空间的栈顶
pop ax,将从当前栈空间的取出栈顶元素,并放入到寄存器ax中。
------
栈空间:10000H-1000FH,栈的段寄存器时1000H,偏移地址是:000F+1,也就是0010H,栈空的时候栈顶是指定000F+1;也就是SS:SP,1000H:0010H
--------
栈段:将一组内存单元定义为一个段;
栈顶的变化范围是0-FFFFH,从栈空时候的SP=0,一直压栈,直到栈满时SP=0;如果再次压栈,栈顶将环绕,覆盖了原来栈中的内容。栈是临时存放数据的,主要是为函数的封装,就是局部变量,局部变量是随着函数的结束而结束。执行函数就是入栈,结束函数就是出栈,栈恢复原来的数据。栈可以重复使用,而不影响栈中的存放的内容。
-----------
-------------
程序的编译与运行
1、使用汇编语言编译程序(masm.exe)对源程序文件中的源程序进行编译,产生目标文件(.obj);
2、再用连接程序(link.exe)对目标文件进行连接,生成可在操作系统中直接运行的可执行文件。
操作系统会依照可执行文件中的描述信息,将可执行文件中的机器码和数据加载入内存,并进行相关的初始化(比如:设置CS:IP执行第一条要执行的指令),然后由CPU执行程序。
----------
源程序
汇编指令:mov ax,0123H
伪指令:除了汇编指令没有对应的机器码的指令,最终不被CPU所执行。伪指令是由编译器执行的指令,编译器根据伪指令来进行相关的编译工作
assume cs:codesg 将段寄存器cs放代码段codesg
codesg segment
start:mov ax,0123H
mov bx,0456H
add ax,bx
add ax,ax
mov ax,4c00H
int 21h
codesg ends
end
segment和ends是一对成对使用的伪指令,这是在写可被编译器编译的汇编程序时,必须要用到的一对伪指令。它们是定义一个段,一个段有一个段名,段名 segment,段名 ends;这里的段名为codesg。ends是段的结束。
一个汇编程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。一个有意义的汇编程序中至少有一个段。
end是一个汇编程序的结束标记,编译器在编译汇编程序的过程中,如果碰到了伪指令end,结束对源程序的编译。
assume:寄存器与段的关联假设,它假设某一段寄存器和程序中的某一个segment...ends定义的段相关联。
-------------------
将源程序中的所有内容称为源程序,将源程序中最终由计算机执行处理的指令或数据,称为程序。
程序最先以汇编指令的形式存在源程序,经编译、连接后转变为机器码,存储在可执行文件中。
--------
codesg:放在segment的前面,作为一个段的名称,这个段的名称最终将被编译 、连接程序处理为一段的段地址。
--------
dos中的程序运行。
dos是一个单任务操作系统。
一个程序在P2在可执行文件中,则必须有一个正在运行的程序P1,将P2从可执行文件中加载入内存后,cpu的控制权交给P2,P2才能得以运行。P2开始运行后,P1暂停运行。p2运行完毕后,应该将CPU的控制权交还给它得以运行的程序P1,此后,p1继续运行。就像cmd命令窗口,运行p1.exe文件,cmd.exe暂停运行,等p1.exe程序运行完成,cmd.exe才能继续运行。这个过程称为:程序的返回
-----------
如何程序返回?
mov ax,4c00H,int 21H就是程序返回(固定格式),这里int不是数据类型int,就是中断技术。
-------
masm 1.asm;编译文件
link 1.obj;连接,当源程序很大时,可以将它分为多个源程序文件来编译,每个源程序编译成为目标文件后,再用连接程序将它们连接到一起,生成一个可执行文件。程序中调用了某个库文件中的子程序,需要将这个库文件和该程序生成的目标文件连接在一起。一个源程序编译后,得到了存有机器码的目标文件,目标文件中的有些内容还不能直接用来生成可执行文件,连接程序将这此内容处理为最终的可执行文件。
--------------------------
操作系统的外壳
操作系统是由多个功能模块组成的庞大、复杂的软件系统。任何通用的操作系统,都要提供一个称为shell(外壳)的程序,用户(操作人员)使用这个程序来操作计算机系统工作。
1)在dos中直接执行1.exe时,是正在运行的command将1.exe中的程序加载到内存.
2)command设置CPU的CS:IP指向程序的第一条指令(即程序的入口),从而使程序得以运行
3)程序运行结束后,返回到command中,CPU继续运行Command.
-----------
利用debug程序执行过程的跟踪
assume cs:abc
abc segment
start: mov ax,2
add ax,ax
add ax,ax
mov ax,4c00H
int 21H
abc ends
end start
start是程序的入口,start可以任意命名,
------------
debug 1.exe 程序跟踪
可以查看程序的内存加载情况,
exe文件中的程序的加载过程:
1、程序加载后,ds汇总存放着程序所在内存去的段地址,这个内存去的偏移地址为0,则程序所在的内存去的地址为ds:0
2、这个内存去的前256个字节中存放的是PSP,dos用来和程序进行通信。
3、从256字节处后的空间存放的是程序。
上面的程序,
ds=1502,cs=1512;刚好ds于cs相差256个字节。
使用p命令执行int 21;当指令是 int 21H利用p命令
---------------------------------------
---------------------------------------
第五章:[BX]和loop指令(循环)(第五章)
在asm中写命令:
mov ax,2000H
mov ds,ax
mov a1,[0]
mov bl,[1]
....
并不是把[0]为[address]偏移地址,而是当作0;[1]当做1,存放在bl寄存器中。一定要先将偏移地址放入bx寄存器中,然后用mov al,[bx]:整体是 mov bx,0 mov al,[bx];代表debug中使用mov ax,[0];
---
mov ax,[bx]:bx中存放的数据作为一个偏移地址EA,段地址SA默认在ds中,将SA:EA处的数据送入ax中。
mov [bx],ax:功能中存放的数据作为一个偏移地址EA,存放ax的数据。
inc bx;就是bx=bx+1,相当于++bx;自增的意思
-----------------
loop指令,利用cx中存放循环次数;
assume cs:code
code segment
mov ax,2
mov cx,11
s: add ax,ax
loop s
mov ax,4c00h
int 21h
code ends
end
---
loop s指令所要做的事
1、(cx)=(cx)-1;
2、判断cx的值,不为0则转至标号s所标识地址处执行(这里的指令是add ax,ax),如果为零则执行下一条指令(这里是mov ax,4c00h)
--------
程序
assume cs code
code segment
start: mov ax,offffh
mov ds,ax
mov bx,6
mov al,[bx]
mov ah,0
mov dx,0
mov cx,3
s: add dx,ax
loop s
mov ax,4c00h
int 21 h
code ends
end start
注:在汇编源程序中,数据不能以字母开头的,这里0ffffh代表的就是ffffh,
---
mov ax,offffh
mov ds,ax ;设置数据的段地址为ffffh,因为只能数据段寄存器只能使用ax寄存器进行指定;
mov bx,6
mov al,[bx],[bx]是偏移地址,只能先将6放在寄存器,然后再用[bx]代表偏移地址[6];这里是将ffff:0006的内存字节单元放入到ax中低位寄存器al中,ax是字单元,代表两个字节,所以单独使用al,[bx];上面的指令可以改成mov al,ds:[6]
mov ah,0;将ah寄存器置零
mov dx,0;将寄存器dx置零
mov cx,3 设置循环次数为3
s:add dx,ax
loop s ,进行循环,将ax值送入到寄存器中,因为dx为0,第一次循环是dx=ax,第二次循环是dx=dx+ax,也就是dx=dx+ax=2dx,第三次循环dx=dx+ax=2ax+ax=3ax=3dx,就是对dx乘以3的操作
----------------
可以利用命令G+地址(下一条指令地址)跳到循环下一条指令的位置,可以跳出循环。可以用命令u查看程序在内存存放的地址。也可以用p命令跳出循环,执行下一条指令。
------------
一段安全的空间:0:200-0:2ff的256个字节是安全的。
原文地址:https://www.cnblogs.com/lazyli/p/10923912.html