不以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:代表着 ...
随机推荐
- python遗留问题
def assert_element_in_page_source(s): print type(s) print s #assert s in driver.page_sourcecommand=' ...
- CentOS7搭建Gitlab详细过程
1.参见Gitlab官网说明 原文地址:https://about.gitlab.com/install/#centos-7 1.安装并配置必要的依赖项 在CentOS 7(和RedHat / O ...
- 20145204《java程序设计》课程总结
---恢复内容开始--- 20145204<java程序设计>课程总结 每周读书笔记链接汇总: · 20145204<java程序设计>第一周总结 · 20145204< ...
- Linux下查找大文件,大目录的方法
查找大文件 //列举出当前目录所有大于800M的文件 find . -type f -size +800M 1 2 第一个方法只用到了一个命令find,它能够帮我们做一些文件查找的操作.它常用的参数有 ...
- Pandas 练习题
1. 使用 pandas 中的函数,下载上证综指过去一段时间的数据,进行数据探索. 上证综指,全称是上海证券综合指数,是以上证所挂牌上市的全部股票为计算范围,以发行量为权数的加权综合股价指数.这一指数 ...
- install ros-indigo-camera-info-manager
CMake Warning at /opt/ros/indigo/share/catkin/cmake/catkinConfig.cmake: (find_package): Could not fi ...
- S4 继承
S3 系统是宽泛且灵活的,同类的 S3 对象也可能有不同的成员.但是,对于 S4 系统,就不会发生,也就是说,当我们创建一个属于某类的 S4 对象实例时,不能任意添加不在类表示中的字段.举个例子,在创 ...
- vue双向绑定原理及实现
vue双向绑定原理及实现 一.总结 一句话总结:vue中的双向绑定主要是通过发布者-订阅者模式来实现的 发布 订阅 1.单向绑定和双向绑定的区别是什么? model view 更新 单向绑定:mode ...
- PistgreSQL9.6手册(基础摘录)
学习目的:基础使用. 能够开发RoR就行. git: https://github.com/postgres-cn/pgdoc-cn 1.2. 架构基础 PostgreSQL使用一种客户端/服务器的模 ...
- UVA-11988 Broken Keyboard (a.k.a. Beiju Text) (链表 或 递归)
题目大意:将一个字符串改变顺序后输出.遇到“[”就将后面内容拿到最前面输出,遇到“]”就将后面的内容拿到最后面输出. 题目分析:用nxt[i]数组表示i后面的字符的下标,实际上就是以字符i为头建立链表 ...