使用GCC实现一个没有main方法的程序.

  |   0 评论   |   1,006 浏览

一段普通的main方法看起来是这样:

#include <stdio.h>

int main(int argc, char** argv){
    printf("hello world\n");
}

然后直接编译运行:

gcc main.c && ./a.out

# 输出如下:

hello world

但是这个main函数真的是入口吗.我们先尝试运行一下程序.在main函数这里打一个断点:

image.png

这里发现并没有发现main函数之前还有调用堆栈. 真的是这样的吗?

我们用clion看看, 这里我们就不再被 GDB蒙蔽. 确实我们的main函数不是最外层的函数. 上面还有: __lib_start_main以及 _start函数:

image.png

我们反汇编看一下编译出来的结果.

这里可以用 objdump工具来完成反汇编.但是为了更清晰的展示代码. 这里直接使用了 clion的反汇编结果.

image.png

这里可以看到 _start只是一段 stub的汇编代码.

// 在Linux上,则是前`6`个参数通过`rdi`,`rsi`,`rdx`,`rcx`,`r8`,`r9`传递,
// 其余的参数按照从右向左的顺序压栈。
_start:
	xor    %ebp,%ebp       # ebp清零 , 让EBP -> stack顶(栈增长方向为 高->低)
	mov    %rdx,%r9	       /* Address of the shared library termination
		                  function.  */
	pop    %rsi	       /* Pop the argument count.  */
                               # makes **argc** go into **%rsi**
	mov    %rsp,%rdx       /* argv starts just at the current stack top.  */
	and    $0xfffffffffffffff0,%rsp  
                               /* Align the stack to a 16 byte boundary to follow the ABI.*/
	push   %rax	       /* Push garbage because we push 8 more bytes.  */
	push   %rsp	/* Provide the highest stack address to the user code (for stacks
	   which grow downwards).  */
	mov    $0x4005c0,%r8
	mov    $0x400550,%rcx
	mov    $0x400526,%rdi
	call   0x400410                   ; <__libc_start_main@plt>
	hlt

这段代码大意是在从启动时的寄存器与栈信息中获取相应的参数.然后给调用 __libc_start_main做准备.这个符号函数的参数定义如下:

	/* Extract the arguments as encoded on the stack and set up
	   the arguments for __libc_start_main (int (*main) (int, char **, char **),
		   int argc, char *argv,
		   void (*init) (void), void (*fini) (void),
		   void (*rtld_fini) (void), void *stack_end).
	   The arguments are passed via registers and on the stack:
	main:		%rdi
	argc:		%rsi
	argv:		%rdx
	init:		%rcx
	fini:		%r8
	rtld_fini:	%r9
	stack_end:	stack.	*/

下面是一段crt0.s 代码. 参考维基百科的注释Crt0 - Wikipedia.我直接贴在这里 , 下面的代码是没有连接C运行时的代码. 有些不一样.不过可以参考其大致含义.:

image.png

然后 _start会再调用: __lib_start_main 最后才进入到我们的 main方法.

评论

发表评论


取消