研究实验4

研究过程:

问题引出:C语言编程非得用主函数main吗,不用是否可以?

对此问题进行研究,用tc.exe书写代码如下:

图1  没有main函数的c程序

对其进行编译,链接发现,编译阶段可以完成,但是链接阶段无法完成。即无法通过这种方式生成.exe文件。并显示错误信息:

图2  f()程序提示错误信息

错误信息提示没有定义在c0s中没有定义main。

用link.exe对其生成f.exe文件,查看其汇编代码如下:

图3  f.c对应汇编代码

从图中可以看出来,f()的偏移地址是0,这个与main函数不同,使用g命令

G 1d发现无法返回,且DOS卡死!f.exe的代码共1Dh(29)个字节。

图4  m.c汇编代码

可以发现,m.exe程序比f.exe程序多一条ret语句,即m.exe有30个字节,且程序能够正常返回,且程序执行完076a:0217处的指令就返回。

由此可见,main函数与f.exe首先在偏移地址上就不同f.exe偏移地址是0000h,main函数偏移地址是01fah,其次main函数比f.exe多一条ret指令,使得程序能够正常返回

问,添加了这样一条语句,为什么无法执行,且还会导致dos环境崩溃???!!!!!

问题2:main函数结尾的两个ret分别具有什么含义?

图5  探究ret追踪调用main 函数的地址

易知,call指令占用三个字节,当单步执行ret的时候,我们发现,ip变成了011d,基于之前学习对于cs:ip的理解,我们断定,“call main”的偏移地址为011a,结果如下图:

图6  调用main函数指令地址

由图可以发现,偏移地址确实是地址确实是011a。

下面对c0s进行研究:

将c0s.obj生成.exe文件,并用debug加载,查看汇编代码:如下

图7-8  c0s.exe开头对应汇编代码

图9-10 m.exe开头对应汇编代码

通过观察发现,开头处的汇编语句,出了第一句对DX的赋值不同以外,其余都是相同的。

图11 m.exe调用main处汇编代码

图12  c0s.exe相同偏移处代码

从图7-图12我们可以发现,c0s.exe和我们任意的一个m.exe程序很多内容都是相同的。通过图中第一处红线我们还可以发现,main是c0s.exe的一个实参,即调用main函数的是c0s.exe这个程序!!还可以发现,其余存在很多相同的内容,应该是资源配置的初始化,总之,在这里,我们得到的最重要一条结论就是:main函数被c0s.0bj文件调用!!!随着以后编译环境的改变,或者C语言学习的深入,我们仍然要注意这个本质性问题,虽然对于我们学习语言本身没多大帮助,但对于理解其工作机制却很有帮助!

通过上述,我们知道,main函数只不过是一个入口参数而已,并不具有特殊性。因此,我们想办法看能不能不用main函数编程,首先我们重写一个c0s.asm程序,对其编译,替换原c0s.obj。重新编译连接f.c,发现可以成功对f.c编译连接!!我们直接运行f.exe ,发现程序可以正常运行并返回!如下图

图13 得以正常运行的f.exe

我们通过debug加载f.exe,u命令查看开始处代码:如下

图14-15  debug加载f.exe

通过代码,我们发现,程序将我们自己写的c0s代码也加载进去了,再次印证了以下观点:1.c0s文件和用户obj文件一同连接,生成相应的exe文件;2.所谓的main,f不过是一个入口参数而已,本身并无特地位!

下面重新研究向一块安全的内存中写入”a”到”h”,汇编代码如下:

图16-19 安全空间写入”a”到”h”

我们可以发现一个很奇怪的现象,程序中经常刷新es寄存器的值!!!

图20-21  内存结果显示

可以看出ds:0开始处存放额是a-h,在这里我们需要注意的是,es只管下一条语句的段地址!之后默认的是ds!务必明确这一点!

未解决的问题:

Main函数的结尾处为什么有两个ret?

对于向安全的空间写数据,为什么会经常刷新es寄存器的值?

总结感悟:

对于这次学习我认为学习到最重要的一点是对MIAN函数的认识更加深刻了,即MAIN函数本身并不具有一定的特殊性!仅此而已。期间对于追踪调用MAIN函数指令地址进行了思考,并最终通过实践得到了验证。此次研究我认为对于编程技巧没有太大的帮助,但是对于理解本质却很有帮助,另外,对于最后一个向安全空间写数,我认为还任由许多问题应该探讨!

main函数是必须的吗的更多相关文章

  1. [C#] 了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数

    了解过入口函数 Main() 吗?带你用批处理玩转 Main 函数 目录 简介 特点 方法的参数 方法的返回值 与批处理交互的一个示例 简介 我们知道,新建一个控制台应用程序的时候,IDE 会同时创建 ...

  2. 选择目录,选择文件夹的COM组件问题。在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。

    异常: 在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式.请确保您的 Main 函数带有 STAThreadAttribute 标记. 只有将调试器附加到该进程才会引发此异常. ...

  3. eclipse的maven项目,如何使用java run main函数

    项目使用maven管理,一般说来就使用jetty:run了.但是对于做功能测试和集成测试的用例,需要使用自定义的quickrun来运行进行测试环境的参数设定和功能隔离,google一番发现maven有 ...

  4. [汇编与C语言关系]2. main函数与启动例程

    为什么汇编程序的入口是_start,而C程序的入口是main函数呢?以下就来解释这个问题 在<x86汇编程序基础(AT&T语法)>一文中我们汇编和链接的步骤是: $ as hell ...

  5. 【Go入门教程3】流程(if、goto、for、switch)和函数(多个返回值、变参、传值与传指针、defer、函数作为值/类型、Panic和Recover、main函数和init函数、import)

    这小节我们要介绍Go里面的流程控制以及函数操作. 流程控制 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的流程描述来表达很复杂的逻辑.Go中流程控制分三大类:条件判断,循环控制和 ...

  6. linux c 笔记-2 Hello World & main函数

    按照惯例撸一个hello_world.c #include <stdio.h> int main(int argc, char * argv[]) { printf("hello ...

  7. Spark&Hadoop:scala编写spark任务jar包,运行无法识别main函数,怎么办?

    昨晚和同事一起看一个scala写的程序,程序都写完了,且在idea上debug运行是ok的.但我们不能调试的方式部署在客户机器上,于是打包吧.打包时,我们是采用把外部引入的五个包(spark-asse ...

  8. [ASM C/C++] C语言的main 函数

    C语言有两种可能的运行环境 1. 独立(freestanding) 在独立环境中,C程序执行不需要操作系统的支持,因此只具有最小的链接库能力. 2. 宿主(hosted) 在宿主的环境中,C程序会在操 ...

  9. main函数的详解

    public : 公共的. 权限是最大,在任何情况下都可以访问. 原因: 为了保证让jvm在任何情况下都可以访问到main方法. static: 静态.静态可以让jvm调用main函数的时候更加的方便 ...

  10. Linux中Main函数的执行过程

    1. 问题:Linux如何执行main函数. 本文使用一个简单的C程序(simple.c)作为例子讲解.代码如下, int main() { return(0); } 2.  编译 -#gcc -o ...

随机推荐

  1. python中remove的一些坑

    前几天,使用python时遇到这么一个需求,删除一个列表中值为1的元素.我寻思着使用remove方法,但是remove方法只会删除第一个,于是我使用for循环去删除.代码和运行结果如下: 当时这个结果 ...

  2. 用Python做股市数据分析(二)

    本文由 伯乐在线 - 小米云豆粥 翻译.未经许可,禁止转载!英文出处:Curtis Miller.欢迎加入翻译组. 这篇博文是用Python分析股市数据系列两部中的第二部,内容基于我在犹他大学 数学3 ...

  3. percona-toolkit大表操作DDL使用

    1. 系统与安装数据库 [root@zhang ~]# cat /etc/redhat-release # 也可以使用其他版本 CentOS Linux release (Core) [root@zh ...

  4. 使用python scrapy爬取知乎提问信息

    前文介绍了python的scrapy爬虫框架和登录知乎的方法. 这里介绍如何爬取知乎的问题信息,并保存到mysql数据库中. 首先,看一下我要爬取哪些内容: 如下图所示,我要爬取一个问题的6个信息: ...

  5. [原创]Javascript模拟“类”的综合实现方式以及部分细节【截至ES6】

    [原创]Javascript模拟“类”的综合实现方式以及部分细节[截至ES6] 前言   最近几个旧项目里使用的图片编辑插件出现Bug, 经Review 后确定需要在其内外均做些改动,但是头疼的发现部 ...

  6. selenium 初探

    # -*- coding:utf-8 -*- from selenium import webdriver driver = webdriver.Firefox() # 打开firefox浏览器 dr ...

  7. css固定背景图位置 实现屏幕滚动时 显示背景图不同区域

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. 【BZOJ3622】已经没有什么好害怕的了

    Description 已经使 Modoka 有签订契约, 和自己一起战斗的想法后 , Mami 忽然感到自己不再是孤单一人了呢. 于是, 之前的谨慎的战斗作风也消失了 , 在对 Charlotte ...

  9. centos7下安装docker(13.1docker存储--data volume)

    我们现在知道docker 有两种存储方式:storage driver和data volume stroage driver这种存储方式主要是存储那些无状态的数据,是镜像层和容器层组成的,而data ...

  10. 如何用命令行刷新,启用,禁用Magento2的缓存

    当你使用Magento商店时如何刷新Magento 2中的Cache命令行是基本的常用操作.Magento 2默认有12种缓存类型.在命令行中有5个简单的命令来管理缓存.在这篇文章中,我将逐步向您展示 ...