不同操作系统下的程序入口点分析

来源:互联网 发布:php初学者,环境搭建 编辑:程序博客网 时间:2024/04/30 06:15

转自 http://hi.baidu.com/liu_bin0101/blog/item/03e3a9ec4e0fd5d72e2e21b9.html

程序入口与编译器没有什么关系, 关键是链接链接器(UNIX的用的ld和WINDOWS下用的LINK.EXE)
ld 用参数-e entry参数指定程序入口为entry
LINK.EXE 用/ENTRY:symbol指定程序入口为symbol
通常, ld/LINK.EXE 不是被直接运行的, 而是由编译器用适当的参数去调用的.
C/C++编译器的完成编译之后会用适当的参数去调用ld/LINK.EXE告诉链接器程序的入口.
WINDOWS下VC编译的程序程序入口点是WinMainCRTStartup(/SUBSYSTEM:WINDOWS, WIN32 GUI 程序)或mainCRTStartup(/SUBSYSTEM:CONSOLE 即WIN32控制台程序).
UNIX下cc/gcc设置的缺省程序入口是_start.

不论是WinMainCRTStartup, mainCRTStartup还是_start, 在链接器生成可执行程序之后, 入口点信息都保存在可执行文件中了.
WinMainCRTStartup, mainCRTStartup或_start函数都是由C标准库实现的, 这些里面通常做一些初始化工作, 包括一些需要用汇编语言才能完成的工作, 然后调用的main函数(WIN32 GUI 程序是WinMain).
这个过程可以用一个例子来说明, 下面是FreeBSD 6.2 的libc的crt1.c, 里面有_start函数的实现:
C/C++ code
/* LINTLIBRARY *//*- * Copyright 1996-1998 John D. Polstra. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#ifndef lint#ifndef __GNUC__#error "GCC is needed to compile this file"#endif#endif /* lint */#include <stdlib.h>#include "libc_private.h"#include "crtbrand.c"extern int _DYNAMIC;#pragma weak _DYNAMICtypedef void (*fptr)(void);extern void _fini(void);extern void _init(void);extern int main(int, char **, char **);extern void _start(char *, ...);#ifdef GCRTextern void _mcleanup(void);extern void monstartup(void *, void *);extern int eprol;extern int etext;#endifchar **environ;const char *__progname = "";static __inline fptrget_rtld_cleanup(void){ fptr retval;#ifdef __GNUC__ __asm__("movl %%edx,%0" : "=rm"(retval));#else retval = (fptr)0; /* XXXX Fix this for other compilers */#endif return(retval);}/* The entry function. */void_start(char *ap, ...){ fptr cleanup; int argc; char **argv; char **env; const char *s;#ifdef __GNUC__ __asm__("and $0xfffffff0,%esp");#endif cleanup = get_rtld_cleanup(); argv = &ap; argc = *(long *)(void *)(argv - 1); env = argv + argc + 1; environ = env; if (argc > 0 && argv[0] != NULL) { __progname = argv[0]; for (s = __progname; *s != '\0'; s++) if (*s == '/') __progname = s + 1; } if (&_DYNAMIC != NULL) atexit(cleanup); else _init_tls();#ifdef GCRT atexit(_mcleanup);#endif atexit(_fini);#ifdef GCRT monstartup(&eprol, &etext);#endif _init(); exit( main(argc, argv, env) );}#ifdef GCRT__asm__(".text");__asm__("eprol:");__asm__(".previous");#endif__asm__(".ident\t\"$FreeBSD: src/lib/csu/i386-elf/crt1.c,v 1.14 2005/05/19 07:36:07 dfr Exp $\"");
至于楼主想知道的"如何让没有main函数的C程序变成可执行文件?" 涉及到自己链接给链接程序传参数, 有一个例子可以试试.
C/C++ code
/*- * name: entry_start.c * auth: mymtom * date: 2008-02-18 */#include <unistd.h>#include <string.h>void_start(void){ (void)write(1, __func__, strlen(__func__)); (void)write(1, "\n", 1); _exit(0);}

这个程序在FreeBSD 6.2 和Fedora Core 6上可以用下面的命令编译, 也可以运行.
gcc -c entry_start.c
ld -o entry_start -static -e _start entry_start.o -lc
但是在运行Loongson Debian Linux V4.0的龙芯福珑迷你(龙芯2E处理器)的机器上会core dump,
原因应该是没有初始化C运行环境而调用了C库函数引起的. 毕竟这不是写C程序的正规方法