4

终于来到了研究实验4这次的实验是看看不用main函数,能不能编写正确的程序,直接来试一试,果然报错了

4_第1张图片
与之对应的是三个问题

  1. 编译和连接哪个环节会出问题?
  2. 显示出的错误信息是什么?
  3. 这个错误信息可能与哪个文件相关?

很显然,显示link环节出现问题,显示出的错误信息也很明了undefined symbol ‘__main’ in module COS 看出来和main函数有关,在之前安装环境时记得程序需要一个COS.obj文件才可以继续运行,所以猜想和这个文件有关

接下来,使用之前的link对obj文件进行链接并用debug查看,结果如图所示

4_第2张图片

之后观察发现,进去前面没有任何多与的东西直接就是写的f函数,有这么几个思考的问题

  1. f.exe的程序代码总共有多少字节?
  2. f.exe能正确返回吗?
  3. f函数的偏移地址是多少?

从图中可以看出f.exe程序代码只有1C也就是29个字节

4_第3张图片

可以看出程序不能正常返回,报错

f函数的偏移地址呢也就是程序开头,一进去程序就是f函数

然后呢,写一个正常的main函数里面函数体中写一样的代码,之后用debug进行单步跟踪
4_第4张图片

可以看出已经和前面的不一样了这里有三个问题

  1. m.exe的程序代码总共有多少字节?
  2. m.exe能正确返回吗?
  3. m.exe程序中的main函数和f.exe中f函数的汇编代码有何不同?

这里第一个问题有点疑惑,第二个正常显示,第三个呢跳转到1f0观察汇编代码只不过可以看出之后多了个RET然后又去进行一些别的事情

之后用debug对m.exe进行单步跟踪,使用g指令直接执行if0处,发现程序直接正常结束并显示正确退出

4_第5张图片

思考以下几个问题

  1. 对main函数调用的指令和程序返回的指令是哪里来的?

可以看出直接用link连接obj文件,程序是不能正确执行也不能正确结束的,而编译在一起就可以正确执行

  1. 没有main函数的信息时出现错误的信息里有和“c0s”相关的信息,而前面在搭建环境里时,没有c0s.obj就无法连接,是不是链接在一块就可以链接生成.exe文件,
  2. 对用户程序的main函数进行调用的指令和程序返回的指令是否就来自obj文件
  3. 我们如何看出c0s.obj文件中的程序代码呢?
  4. c0s.obj文件里有我们设想的代码吗?

初步设想,也不能断定和c0s.obj链接后就可以生成.exe文件不过生成.exe文件一定与其有关,如何可以看到其中的代码呢,直接拿link链接应该就可以,接下来就进行初步探索

用link.exe对cos.obj进行连接,生成cos.exe,观察汇编代码,

4_第6张图片
4_第7张图片

前面的代码都一样,到了这时稍微有些不同,
4_第8张图片

4_第9张图片
暂时没搞懂这些做法具体原因,不过继续往下看时候发现了这

在这里插入图片描述
在m.exe中发现了执行01fa的代码,之后用-p指令进行执行,发现程序正常执行了,而观察C0S.exe时却发现

4_第10张图片

直接跳转到011D好像这样不太明显,刚刚执行m.exe时函数执行返回后也是011D
在这里插入图片描述

由此可以推断,链接了C0S.exe之后的程序其实是有程序调用他之后再进行返回,接着继续执行m.exe发现到了这

4_第11张图片
到最后直接就正常退出了,说明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,发现链接成功。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PAvNeOx4-1592028504135)(/home/bys/.config/Typora/typora-user-images/image-20200610104136891.png)]

我们debug加载反编译后,其代码如下:

4_第12张图片

我们看到,这里的call的偏移地址是0012,是我们F函数的第一条语句。运行后发现:

在这里插入图片描述
程序正常返回。这也就是说,我们编写的C0S.obj已经实现了调用返回的功能。

  1. 研究一个程序

我们编写一个程序如下:

4_第13张图片

我们看到,这个程序与上次程序不同点在于,Buffer没有申请内存,而是直接赋值为零。我们猜测,所写入的位置为ds:[0]。我们验证:

4_第14张图片

我们看到,a-f这个个字母就是写到了DS:[0]处

研究体会:

通过这次实验了解到编译器为用户编写好的一个程序背后作了什么,还算挺有收获,也知道main函数之前的一些行为,但对其具体行为并不算很了解,还有待探索

你可能感兴趣的:(笔记)