(一) 研究目的

使用C语言编程,我们一定要使用main函数么?

(二) 研究过程

1) 最初的程序

首先,我们编写一个不写main函数的C语言程序。

程序如下:

在编译的过程中,没有发现错误。在链接的过程中发现出现的错误如下:

链接时出现Undefined symbol ‘_main’ in module c0s

这样的错误信息,可能main函数与c0s.obj这个文件有关系。

这时我们想,C语言编译之后的文件后缀名是什么?是.obj。那汇编语言编译后的文件名是什么?也是.obj。这两个文件有关联么?

理论上说,他们的内容应该是相似的。而且都应该可以被link.exe编译。

我们尝试link:

我们发现没有错误。

2) 带main函数的程序

我们编写带main的函数的程序

我们编译链接。得到m.exe

3) 找不同

我们带main和不带main的C语言程序都编译连接成了.exe,那我们就来找找他们的不同。代码是相同的,不同的只是main的有无,那不同点就只集中在main上面。这样,我们就可以集中的针对main的功能进行研究。

首先我们看一下文件详情。

我们看到,F.exe和M.exe大小还是差很多的。结合我们以前debug时看到的,在编译链接后程序第一条语句之前有很多未知的程序。我们分析,可能是M中有main函数,这使得在编译连接过程中,给程序多增加了很多语句。

我们分别运行这两个程序。

程序的运行结果如下:

我们看到两者的运行情景均如上所示,区别是M.exe运行后返回dos中,而F.exe运行后直接卡死。

原因是什么呢?我们想到在研究二中查看函数实现的时候,在main函数中有ret指令。当时我们分析,这是因为C语言将main函数也实现为了子程序。是不是程序没有返回呢?

我们继续分析不同。我们用debug加载。

首先查看两者的-r和-g的情况:

这里我们直观的看出,程序M的代码段长度为0EB8,程序F的代码段长度为001D。且程序M执行后可以正确的返回,而程序M执行后则不能返回。

在查看其反汇编后的代码:

F.exe如下:

M.exe如下:

中间部分不再赘述

我们可以看到,在函数内的实现有一处不同,在F.exe中,缺少三条指令,RET;PUSH BP;MOV BP,SP;(分号只是为了区分语句)。这是main函数返回,恢复寄存器BP的语句。

还有一处不同,是01fa前所增加的部分,在F.exe中是没有的。

那我们来分析一下增加的这部分代码。

基于我们前面的认识,首先,main被作为了一个子程序;第二,编译时为main添加了很多代码。那是不是添加的代码调用了main并且实现了程序正确返回的功能呢?

我们查看前面增加的代码,我们知道main的偏移地址是01FA,那我们就找有没有类似call 01FA的语句。我们最后在这里发现了:

这说明,我们的猜想是正确的,main函数前的这些程序,调用了main函数。而且,我们发现了如下的代码:

我们执行到这里:

这说明什么?main前添加的程序有这么两个功能,第一,调用main函数;第二,使得程序正确返回。当然,还有其他的功能,但是这两个功能是最基本的。

4) C0S的作用

我们刚才看到,没有main函数的程序在链接的时候会出现COS文件的错误,而C0S文件是一个.obj文件。那么,他是不是能够被链接成为一个.exe文件呢?如果可以,那我们就可以看到其汇编代码。

虽然有错误,但是生成了C0S.exe。我们debug加载查看。

我们看到,C0S中的代码与main前所加的代码基本相同。也就是说,我们可以认定,main前面的程序与C0S有关。

5) 程序生成exe的过程

援引书中的话:

tc.exe将c0s.obj和用户.obj一同连接,生成.exe。照这个方法生成的exe程序运行过程如下:

①c0s.obj里的程序先运行,进行相关的初始化。如申请资源,设置ds,ss等相关寄存器。

②c0s.obj里的程序调用main函数,从此用户程序开始运行。

③用户程序运行结束从main程序返回到c0s.obj的程序中。

④c0s.obj的程序接着运行,进行相关的资源释放,环境恢复的工作。

⑤c0s.obj的程序调用DOS的int 21h例程的4ch号中断功能,程序返回。

6) 自己编写C0S.obj

基于以上的认识,我们在汇编中编写这样的程序:

编译,并将其复制到minic文件夹下,替换原来的C0S.obj。

我们这时在编译我们原来写的F.C,发现链接成功。

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

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

程序正常返回。这也就是说,我们编写的C0S.obj已经实现了调用返回的功能。

7) 研究一个程序

我们编写一个程序如下:

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

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

(三) 附录研究

我们在TC2.0的环境下发现了C0.asm这样一个文件。我们想,这与C0S.oobj会不会有关联。

我们打开,发现其语句与我们C0S链接之后的语句如此一致:

我们尝试编译链接C0.asm,发现其出现了RULES.ASI,EMUVARS.ASI没有找到的情况。我们拷入,编译成功。发现其反汇编代码如下:

与C0S.obj链接之后的代码相同。这是我们就可以知道,c0.asm就是C0S的源代码。

而我们用记事本打开其他两个文件:

这里面大部分定义的是一些常量。

(四) 研究感悟

main函数还是f函数?这不重要。重要的是程序连接的过程中对程序所添加的修改。为了保证程序可以正常的调用和返回,以及其他的一些功能实现,C语言添加了如此长的代码。透过main看到这个实质,会让我们的学习更加深入一层。

王爽-汇编语言-综合研究四-不使用main函数编程的更多相关文章

  1. 王爽-汇编语言-综合研究一-搭建简易C环境

    (一) 学习过程: 整个过程分为两个部分: 第一:将TC2.0的环境使用虚拟软盘复制到DOS虚拟机中: 打开WinImage,fileànew,由于TC2.0的环境解压后为2.02M,所以我们在Sta ...

  2. 王爽<<汇编语言>> 实验十四

    ;以"年/月/日 时:分:秒"的格式, 显示当前的日期, 时间 assume cs:code code segment main: out 70h,al ;告诉CMOS RAM将要 ...

  3. 王爽汇编语言(第三版)环境搭建(附PDF及工具下载)

    一.前言 最近在学习汇编语言,使用的是读者评价非常高的王爽老师写的<汇编语言>(第三版),为了适应现在各个版本的windows操作系统,所以采用VMWare虚拟机来搭建纯DOS环境. 二. ...

  4. 王爽< 汇编语言>实验十二

    ;此乃安装程序 ;功能:将8086cpu中断类型码为0 的中断向量设置为我们编写的中断服务程序入口地址 ;该中断在除法发送溢出的时候产生 assume cs:code code segment mai ...

  5. 王爽<汇编语言>实验十一 (附测试代码)

    ;名称: letterc ;功能: 将以0为结尾的字符串中的小写字母转变成大写字母 ;参数: ds:si指向字符串首地址 assume cs:code data segment db data end ...

  6. 王爽<汇编语言>实验十

    实验十 3.数值显示(以下程序附带测试程序) ;名称: dtoc ;功能: 将dword型数据转变为表示十进制数的字符串,字符串以0为结尾 ;参数: (ax)=dword型数据低字 ; (dx)=dw ...

  7. Linux下学习王爽老师的汇编语言

    坐起来非常容易,找到这条路确实非常曲折,为了后来的同志们不再纠结,特记录如下: 这几天看汇编语言时,很多人都推荐王爽老师的<汇编语言>,老师的书的确写的很好,但是讲的是ms的汇编,但是总不 ...

  8. 关于《汇编语言(王爽)》程序6.3使用16个dw 0的问题

    在学习王爽老师<汇编语言>的第6.2节时,在程序6.3代码中,给出了如下的代码: assume cs:code code segment dw 0123h, 0456h, 0789h, 0 ...

  9. 王爽汇编第十章,call和ret指令

    目录 王爽汇编第十章,call和ret指令 call和ret指令概述: ret和retf ret指令 retf指令 call 和 ret 的配合使用 call指令详解 call原理 call指令所有写 ...

随机推荐

  1. android 判断sd的状态,所有文件,剩余空间的大小

    public class MainActivity extends AppCompatActivity { String TAG = MainActivity.class.getCanonicalNa ...

  2. java的for循环冒号

    背景:有一个小伙纸问我 下面的java代码是什么意思. for (final RouterInterface routeIface : curNode.getRouteInterfaces()){ … ...

  3. [ 转 ] scrapy 中解决 xpath 中的中文编码问题

    1.问题描述: 实现定位<h2>品牌</h2>节点 brand_tag = sel.xpath("//h2[text()= '品牌']") 报错:Value ...

  4. 写了cookie阻止通过输入地址直接访问下一个html,但是直接输入地址访问时,会闪一下下一个页面,怎么回事啊????、

    描述:做了两个页面login.html   index.html  在index的body加了onload事件,调用一个js,js中有cookie的判断,防止没有登录就打开index.html,如果没 ...

  5. Java和.NET使用DES对称加密的区别

    Java和.NET的系统类库里都有封装DES对称加密的实现方式,但是对外暴露的接口却各不相同,甚至有时会让自己难以解决其中的问题,比如Java加密后的结果在.NET中解密不出来等,由于最近项目有跨Ja ...

  6. List<Object> to JSONArray一

    package com.beijxing.TestMain; import java.util.ArrayList; import java.util.List; import com.beijxin ...

  7. 如何在HTML中加载Flash(2种实现方法)_HTML/Xhtml_网页制作

    点评:如何在HTML中加载Flash,为网页添加更多的色彩,普通的网页以无法满足用户的需求,接下来为大家介绍下2种在HTML中加载Flash的方法,感兴趣的各位可以适当参考下,希望对你有所帮助 第一种 ...

  8. 查看linux中某个端口是否被占用

    1.netstat -tunlp | grep **** -t--tcp  -u--udp -l--listening -n --numeric -p--program -a--all 2.lsof ...

  9. windows下安装composer抛出Composer\Downloader\TransportException异常解决办法

    1. 把默认的 secure-http 改成false composer config -g secure-http false 2. 修改配置文件 #修改全局文件(推荐) composer conf ...

  10. node.js 基础学习笔记3 -express

    1.工作原理 当通过app.js建立的服务器时,会看到一个简单的页面.返回页面时,浏览器会向服务器发送请求.app会解析请求的路径,调用相应的逻辑,调用对应的视图模板,传递对象数值,最终生成HTML页 ...