zoukankan      html  css  js  c++  java
  • 其实一个问题很一困扰很久,也不会有答案,比如说main函数

    一、 学习过程

    编写程序f.c:

     

    对其进行编译,正常通过,再对其进行连接,出现错误:

     

    显示的出错信息为:

     

    翻译成中文是:在c0s模块没有定义符号’_main’。

    那么这个错误信息可能与文件c0s.obj有关。那么是什么原因导致编译出错呢?

    既然已经将程序编译成了obj文件,那么用之前我们经常使用的link.exe能否将它连接呢?结果是可以的:

     

    用debug查看f.exe:

     

    程序是从06fb:0到06fb:001c,一共29个字节。但是整个程序的代码有541字节:

     

    执行最后一条ret指令,返回到b800处:

     

    查看该地址的上一条指令:

     

    发现上一条指令是push ds,不是跳转指令,所f.exe没有正确返回.

    由上图知f函数的偏移地址是0.

     

    编写程序m.c:

     

    对m.c进行编译连接,这一次连接没有出现错误。

    用debug查看m.exe,发现代码还是在1fa处:

     

    程序是从06fb:01fa到06fb:0216,一共29个字节。但是整个程序的代码有4.19KB:

     

     

    程序返回06fb:011d,查看该地址之前的代码:

     

    发现上一条指令是call 01fa,即跳转到主程序所在代码段,所以程序的返回是正确的。

    观察两个程序的汇编代码发现:

    (1)f.exe的偏移地址为0,在debug中直接用u命令就可看到,而m.exe的偏移地址为1fa,在debug中用u命令查看到的不是main函数中的代码。

    (2)f.exe有没有被调用,所以函数返回是错误的,m.exe被调用了,所以函数的返回是正确的。

    由上图知:对main函数进行调用的指令地址为06fb:011a,整个m.exe程序返回的指令是:

     

    我们发现,对main函数进行调用的指令和程序返回的指令都不是我们所写的语句,而是编译或连接过程中提供的。

    没有main函数时,Tc里出现连接错误,提示c0s.obj里的main是没有定义的,而没有c0s.exe就无法对程序进行连接,那么有可能tc是把c0s.obj或者它的一部分与m.exe

    一起进行连接生成exe文件。而且对main函数进行调用的指令和程序返回的指令应该就是c0s.obj所提供的。那么我们要对c0s.obj进行研究,可以用link.exe对它进行连接,再用debug查看汇编代码。发现虽然link提示错误,但是还是生成了c0s.exe文件:

     

    用debug查看c0s.exe和m.exe发现连个程序的代码非常相似,那么m.exe中调用了main函数,c0s.exe中调用了什么呢?

     

    可以看到,c0s.exe中本来应该指向main函数段的地方因为找不到main函数,所以指向了下一条语句。还有这两段程序中call的程序段地址都不一样。

    所以C语言编程一定要写main函数是因为c0s.obj连接后要调用main函数执行其功能,如果我们把main函数写成其他的函数,c0s.obj里的代码不会识别。如f.exe虽然可以由link.exe连接,但是不会被调用,而是直接执行其中的内容,造成返回错误。而书上说c0s.obj的作用是:在程序开始运行,进行相关初始化,再调用main函数,返回后进行相关的资源释放,环境恢复等工作,再将程序返回。那么如果我们改写c0s.obj使其调用的不是main函数而是其他函数,编程时就可以不写main函数了。

    编写c0s.txt:

     

    用masm编译成obj文件,覆盖原来的c0s.obj文件。

    将f.c重新编译连接,这次的连接成功了。

    用debug查看f.exe:

     

     

    发现我们重写的c0s.obj的内容出现在程序中,f函数的偏移地址为0012,且返回正确。f.exe可以正确运行。

    编写新的程序f.c:

     

    这里的实现原理与上一篇的最后一个程序相同,不同的是将main函数换成了f函数,因为我们重写了c0s.obj,所以同样可以执行。但是为什么前者是用malloc函数开辟了20个字节的空间,而后者是直接赋0呢?我觉得应为是200:0的安全空间,所以可以直接使用,但是如果在比较复杂的程序中或者空间比较紧张,则要先开辟空间,这样比较安全。

    二、 解决的问题

    (1) c0s.obj文件的作用:在程序开始运行,进行相关初始化,再调用main函数,返回后进行相关的资源释放,环境恢复等工作,再将程序返回。

    (2) 可否用其他函数代替main函数?

    答:可以,但是要修改c0s.obj文件。

    三、 未解决的问题

    (1) link.exe是集成了c0s.obj、emu.obj等所有编译需要的文件吗?

    (2) 如果不修改c0s.obj,要将f.c编译成功还需要哪些文件?

     

    四、 学习感想

    我们在解决复杂的问题时,要把它分解成一个一个小问题来解决。这次的研究是书上提出了问题来帮助我们理解和思考,但是真正解决问题时是没有人来帮助我们划分问题、提出问题的。所以在平时的学习中,我们要多督促自己养成好的思考的习惯。

  • 相关阅读:
    OleDbCommand 的用法
    递归求阶乘
    C#重写窗体的方法
    HDU 5229 ZCC loves strings 博弈
    HDU 5228 ZCC loves straight flush 暴力
    POJ 1330 Nearest Common Ancestors LCA
    HDU 5234 Happy birthday 01背包
    HDU 5233 Gunner II 离散化
    fast-IO
    HDU 5265 pog loves szh II 二分
  • 原文地址:https://www.cnblogs.com/still-smile/p/13584231.html
Copyright © 2011-2022 走看看