前言
在该系列的第六篇文章我们主要讲述了:关于栈的寄存器:SS和SP的问题
来回一下:
对于栈指针来说,栈在被开辟的时候,首先要通过SS指针去找到开辟栈的地址空间的首地址,随后,SP指针指向该栈空间的末尾的下一个空间处.当执行push指令时,sp会-2 随后将目标压入栈中
当执行pop指令时,会先将元素弹出,随后执行sp+2
还回顾了关于不同段寄存器的作用:
ds与[] 是读取数据
cs:ip是去寻找指令
而ss:sp与栈空间有关.
详情请看我的上一篇文章
Assembly(六)–寄存器总篇章
喜欢的小伙伴点赞关注支持一下~ 博主争取日更哦~
本篇文章我们将去透彻的理解一个完整的程序.
1.1 程序从写出到被执行的过程
- 编写汇编源程序 用汇编语言等语言编写程序的源程序
- 对原程序进行编译 link
这部分可以参照我的另一篇文章:关于C++的编译和链接的新看法
C++ - 执行可执行文件中的程序,有cs:ip指向第一条要执行的指令,然后由cpu执行程序
1.2 源程序的讲解
让我们来实际的看下一段汇编的程序吧
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
关于程序,由以下几点要说明:
伪指令
- 程序中出现的伪指令有:xxx segment xxx ends ,这个segment与ends是成对出现的,表示定义了一个段,这个段是xxx 像是程序中的 段名叫 codesg
- end ,.end是代表着一个汇编程序的结束标志
- assume 用来假设程序的某一个段与某个寄存器相联系,比如 其中的 assume cs:codesg 这里就跟cs寄存器联系起来了
一个汇编程序通常由伪指令和汇编指令组成.经过编译链接后编程可执行文件.
练习:让我们来写一个计算2的三次方的程序吧:
assume cs:cac
cac segment
mov ax,2
add ax,ax
add ax,ax
cac ends
end
十分简单
当我们考虑到:一个程序要有返回值时,问题就来了
1.3 程序的返回
观察之前的程序:
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
我们不难看出有两条指令没有被提到:
mov ax,4c00H
int 21H
这两条指令所实现的功能就是程序返回
我们不必深究为什么,反转在end后面加两条指令就可以实现程序返回.
1.4 实战:
1. 在准备好的dosbox中,使用edit功能:
进行编辑
保存退出为1.asm
随后进行编译
使用masm.exe
这里先输入文件名,随后默认obj文件的名字 随后忽略文件生成列表和交叉引用文件
编译完成!
接下来开始链接:
使用link.exe
在忽略了 lib和无栈段生成后,我们成功的链接了文件.生成了exe文件
链接的作用是什么呢?
首先当程序很大的时候,可以分成多个文件来进行编译,自然链接到一起可以很方便
其次如果程序中强调了某个库文件的子程序,链接也十分必要了.
2. 编译 链接 跟踪
写文件t1.asm
assume cs:codesg
codesg segment
mov ax.2000H
mov ss,ax
mov sp,0
add sp.10
pop ax
pop bx
push ax
push bx
pop ax
pop bx
mov ax,4c00H
int 21H
codesg ends
end
然后进行编译 链接后使用debug进行调试
可以看到目前的cs:ip是在076A:0处
此时的SS是0769 sp为0
执行两次命令后,成功的将ax的值赋值给了ss
接下来就是执行sp的赋值了
其实这里的pop ax就是为了让sp=sp+2
连着两次都是
随后进行push操作 是为了让sp=sp-2