不以main为入口的函数
先看一段程序
#include <stdio.h> void test() { printf("Hello Word!\n"); return 0; }
没有main函数,编译一定不会通过,在gcc下编译会提示以下信息:
/usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o:在函数‘_start’中:
(.text+0x18):对‘main’未定义的引用
collect2: 错误: ld 返回 1
可以看到错误信息提示,提到了一个“crt1.o”这个文件,其中crt是“C runtime library”的缩写,其含义是“C运时库”。
C运行时库除了给我们提供必要的库函数调用(如memcpy、printf、malloc等)之外,它提供的另一个最重要的功能是为应用程序添加启动函数。C运行时库启动函数的主要功能为进行程序的初始化,对全局变量进行赋初值,加载用户程序的入口函数。
从给出的错误提示信息中还可以得知,在crt1.o中,有一个名为“_start”的函数。现在网上找到一份crt1.o的伪代码:
section .text: __start: : init stack; init heap; open stdin; open stdout; open stderr; : push argv; push argc; call _main; (调用 main) : destory heap; close stdin; close stdout; close stderr; : call __exit;
从伪代码可以看出,在这个_start函数中,调用了main函数。那么我们可不可以用什么手段,去修改入口函数,把入口函数改成test函数呢?
gcc test.c -etest -nostartfiles
其中-e选项为修改函数的入口地址,可惜在网上和man手册里都没有找到有关-e这个选项的解释,只搜索到了-E这个选项。问了好多人才明白原来-e指的 就是entrance。这里把entrance指定为test函数。
-nostartfiles选项的作用是通知编译器不自动加入启动函数以及别的库级 别的初始化,这样就不会调用到crt1.o中的_start函数。
此时,编译通过。可是执行程序,可以成功打印出Hello Word!字样,但是却会提示“段错误”。
Hello Word!
段错误
原来,在编译的时候加上了-nostartfiles这个选项的同时,使得最后的return语句不能正常执行。解决方案是,把程序最后的return语句改成exit语句,让exit语句来做最后的“善后工作”。
#include <stdio.h> void test() { printf("Hello Word\n"); exit(); }
没有任何错误。
还有两种方法。。。
方法一:
#include <stdio.h> #define start main int start() { printf("Hello Word\n"); ; }
#include <stdio.h> #define start m##a##i##n int start() { printf("Hello Word\n"); ; }
方法二:
_start函数
_start函数是C程序的入口函数,会调用main函数。在调用main函数之前,会先执行_start函数分配必要的资源,然后再调用main函数。但是在用gcc编译程序时可以使用-nostartfiles选项来重写_start函数。示例程序如下:
#include <stdio.h> #include <stdlib.h> _start(void) { printf("Hello Word\n"); exit(); }
编译指令:
gcc -nostartfiles _start.c -o main.out
反汇编生成的执行程序
a. Disassembly of section .plt: <puts@plt-0x10>: : ff ea pushq <_GLOBAL_OFFSET_TABLE_+0x8> : ff ec jmpq * <_GLOBAL_OFFSET_TABLE_+0x10> 40032c: 0f 1f nopl 0x0(%rax) <puts@plt>: : ff ea jmpq * <_GLOBAL_OFFSET_TABLE_+0x18> : pushq $0x0 40033b: e9 e0 ff ff ff jmpq <puts@plt-0x10> <exit@plt>: : ff e2 jmpq * <_GLOBAL_OFFSET_TABLE_+0x20> : pushq $0x1 40034b: e9 d0 ff ff ff jmpq <puts@plt-0x10> Disassembly of section .text: <_start>: : push %rbp : e5 mov %rsp,%rbp : bf mov $0x400368,%edi : e8 d2 ff ff ff callq <puts@plt> 40035e: bf mov $0x0,%edi : e8 d8 ff ff ff callq exit@plt
不以main为入口的函数的更多相关文章
- 探秘varian:优雅的发布部署程序
上一篇文章<记一次诡异的故障排查经历>中有介绍到我们的部署程序varian,文章发布后有小伙伴对varian很感兴趣,今天就简单的介绍一下我们的varian,揭开她神秘的面纱~ 什么是va ...
- Qt Windows下链接子系统与入口函数(终结版)(可同时存在main和WinMain函数)
Qt Windows下链接子系统与入口函数(终结版) 转载自:http://blog.csdn.net/dbzhang800/article/details/6358996 能力所限,本讨论仅局限于M ...
- C++改变编程入口为main函数
1, 你用vc建了一个控制台程序,它的入口函数应该是main, 而你使用了WinMain. 2. 你用vc打开了一个.c/.cpp 文件,然后直接编译这个文件,这个文件中使用了WinMian而不是m ...
- java main函数不执行?
今天脑袋短路,对于这个问题纠结了好久.这个问题具体是这样的: public class test { public static void main(String[] args) { test2 t ...
- Java面向对象 Main函数 静态的应用 单例设计模式
Java面向对象 Main函数 静态的应用与单例设计模式 知识概要 (1)Main函数的细解 (2)静态的应用,静态变量,静态代码块,静态函数 (3)单例设计模式 1.M ...
- 通过启动函数定位main()函数
如下,通过vc6.0编写一个hello world程序.尝试结合汇编代码.分析启动函数找到main函数. 在printf(xxx)插入断点,调试执行.如下,在堆栈窗口中可见main()下的一个 ...
- java里面main函数为什么要用static修饰
这学期刚开java,因为之前只写过C++和Python没接触过java,有些写法挺不习惯的,今天写完一个程序,run的时候发现提示the selection can't be launched.... ...
- 程序入口函数和glibc及C++全局构造和析构
分类: CRT Machnasim 2011-06-15 17:45 144人阅读 评论(0) 收藏 举报 c++汇编linuxlist语言编译器 1,程序入口函数和初始化 操作系统在装载可执行文件后 ...
- 重新认识Java中的程序入口即主函数各组成部分
主函数各组成部分深入理解 public static void main(String[] agrs) 主函数:是一个特殊的函数,作为程序的入口,可以被JVM调用 主函数的定义: public:代表着 ...
随机推荐
- SQL :模糊查询,转义字符
1. 查询table表name列包含 '_BCE' 的记录 select * from table where name like '_BCE%' ABCEDF _BCEFG _BCEDF 3 row ...
- laravel 项目部署注意事项
1.'Failed to open stream: Permission denied' error - Laravel Laravel >= 5.4 php artisan cache:cle ...
- laravel 多图上传
前台 name="photo[]" 后台获取 $request->file('photo');//获取多个图片循环
- windows下利用批处理脚本监控程序
1.要监控的程序为使用cygwin环境编译的exe可执行文件hello.exe,源码如下: #include <stdio.h> #include <unistd.h> voi ...
- root权限和sudo得到权限的区别
参考: 知乎 命令前加sudo执行和用真正的root用户执行有什么区别?pansz的回答 root用户和sudo使用root权限的区别 变换用户身份为root的方法su 与 sudo root权限和s ...
- SDN前瞻 网络的前世今生
本文基于SDN导论的视频而成:SDN导论 目前网络层面流行的技术概念:虚拟中心:公有云私有云:数据中心等等. SDN主要的模拟器:Mininet OpenDaylight(Cisco) ONOS(AT ...
- 缓存cache(5.2新:redis): gem faker (6600✨) 命令行工具curl(系统内置,可在git上看到文档)
⚠️本章节记录缓存的一些方法的用法案例,配合这篇博客一起阅读:https://i.cnblogs.com/EditPosts.aspx?postid=8776632 前置种子 https://git ...
- jquery.validate验证表单
添加引用 <script src="/${appName}/commons/js/validate/jquery.validate.min.js"></scrip ...
- gruntjs开发实例
Grunt是基于Node.js的项目构建工具.它可以自动运行你所设定的任务,如编译less,sass,压缩js,合拼文件等等. (一)安装nodejs环境,Grunt 0.4.x要求Node.js的版 ...
- java并发编程:线程安全管理类--原子操作类--AtomicIntegerFieldUpdater<T>
1.类 AtomicIntegerFieldUpdater<T> public abstract class AtomicIntegerFieldUpdater<T> exte ...