终于来到了研究实验4这次的实验是看看不用main函数,能不能编写正确的程序,直接来试一试,果然报错了
很显然,显示link环节出现问题,显示出的错误信息也很明了undefined symbol ‘__main’ in module COS 看出来和main函数有关,在之前安装环境时记得程序需要一个COS.obj文件才可以继续运行,所以猜想和这个文件有关
接下来,使用之前的link对obj文件进行链接并用debug查看,结果如图所示
之后观察发现,进去前面没有任何多与的东西直接就是写的f函数,有这么几个思考的问题
从图中可以看出f.exe程序代码只有1C也就是29个字节
可以看出程序不能正常返回,报错
f函数的偏移地址呢也就是程序开头,一进去程序就是f函数
然后呢,写一个正常的main函数里面函数体中写一样的代码,之后用debug进行单步跟踪
可以看出已经和前面的不一样了这里有三个问题
这里第一个问题有点疑惑,第二个正常显示,第三个呢跳转到1f0观察汇编代码只不过可以看出之后多了个RET然后又去进行一些别的事情
之后用debug对m.exe进行单步跟踪,使用g指令直接执行if0处,发现程序直接正常结束并显示正确退出
思考以下几个问题
可以看出直接用link连接obj文件,程序是不能正确执行也不能正确结束的,而编译在一起就可以正确执行
初步设想,也不能断定和c0s.obj链接后就可以生成.exe文件不过生成.exe文件一定与其有关,如何可以看到其中的代码呢,直接拿link链接应该就可以,接下来就进行初步探索
用link.exe对cos.obj进行连接,生成cos.exe,观察汇编代码,
在m.exe中发现了执行01fa的代码,之后用-p指令进行执行,发现程序正常执行了,而观察C0S.exe时却发现
直接跳转到011D好像这样不太明显,刚刚执行m.exe时函数执行返回后也是011D
由此可以推断,链接了C0S.exe之后的程序其实是有程序调用他之后再进行返回,接着继续执行m.exe发现到了这
到最后直接就正常退出了,说明main函数之前的程序还有着这样的作用就是帮助程序正确结束
这个时候就明了了,看来C程序必须从main函数开始不是编译期保证的,也不是链接所保证的,而是通过编译系统提供的obj文件进行程序的正确执行和退出,
之后基于这种机制,对icos.obj进行改写,现在用汇编编写一个程序,尝试去替代原来的c0s.obj
基于以上的认识,我们在汇编中编写这样的程序:
assume cs:code
data segment
db 128 dup(0)
data ends
code segment
start: mov ax,data
mov ds,ax
mov ss,ax
mov sp,128
call s
mov ax,4C00H
int 21H
s:
code ends
end start
编译,并将其复制到minic文件夹下,替换原来的C0S.obj。
我们这时在编译我们原来写的F.C,发现链接成功。
我们debug加载反编译后,其代码如下:
我们看到,这里的call的偏移地址是0012,是我们F函数的第一条语句。运行后发现:
程序正常返回。这也就是说,我们编写的C0S.obj已经实现了调用返回的功能。
我们编写一个程序如下:
我们看到,这个程序与上次程序不同点在于,Buffer没有申请内存,而是直接赋值为零。我们猜测,所写入的位置为ds:[0]。我们验证:
我们看到,a-f这个个字母就是写到了DS:[0]处
研究体会:
通过这次实验了解到编译器为用户编写好的一个程序背后作了什么,还算挺有收获,也知道main函数之前的一些行为,但对其具体行为并不算很了解,还有待探索