《C编译原理》ubuntu下helloword编译连接过程分析

C可执行文件的生成包括如下步骤:预处理、编译、链接;下边分析编译和链接。

一、源程序

vi hello.c

#include <stdio.h>
int main()
{
  printf("helloworld!\n");
  return 0;
}

二、编译及连接

gcc -v hello.c -o hello

......
 /usr/lib/gcc/x86_64-linux-gnu/4.4.6/cc1 -quiet -v -imultilib . -imultiarch x86_64-linux-gnu hello.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -fstack-protector -o /tmp/ccXepOpC.s
......
 as -V -Qy -o /tmp/cc2TF8MY.o /tmp/ccXepOpC.s
......
 /usr/lib/gcc/x86_64-linux-gnu/4.4.6/collect2 --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello -z relro /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../.. /tmp/cc2TF8MY.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crtn.o

1.将C语言编译成汇编语言——cc1

/usr/lib/gcc/x86_64-linux-gnu/4.4.6/cc1 -quiet -v -imultilib . -imultiarch x86_64-linux-gnu hello.c -D_FORTIFY_SOURCE=2 -quiet -dumpbase hello.c -mtune=generic -auxbase hello -version -fstack-protector -o /tmp/ccXepOpC.s

查看:

vi /tmp/ccXepOpC.s

2.将汇编语言编译成目标文件——as

 as -V -Qy -o /tmp/cc2TF8MY.o /tmp/ccXepOpC.s

查看:

readelf -a /tmp/cc2TF8MY.o >hello.o

vi hello.o

3.将目标文件连接成可执行文件——collect2

 /usr/lib/gcc/x86_64-linux-gnu/4.4.6/collect2 --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o hello -z relro /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6 -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../.. /tmp/cc2TF8MY.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-linux-gnu/4.4.6/crtend.o /usr/lib/gcc/x86_64-linux-gnu/4.4.6/../../../x86_64-linux-gnu/crtn.o

查看:

readelf -a hello >hello.bin

vi hello.bin

三、说明

1.上述用到了gcc的cc1和collect2(实际是binutils的ld)、binutils的ar及ld连接器以及glibc的crt*.o(c runtime);所以,没有binutils和glibc的支持、gcc便无法运行。

2.crt*.o文件说明:c runtime;完成执行man函数之前的初始化以及man函数执行完后的扫尾工作。

3.ld默认连接脚本路径:isr/lib/ldscripts/elf32_x86_64.*。

4.elf文件的默认入口点是crt1.o中的_start,不是main:

原因如下,连接脚本决定入口函数:

vi sr/lib/ldscripts/elf32_x86_64.*

......
ENTRY(_start)
......

下面看gcc4.4.6中crt1.o的源码:

glibc-2.14.1/sysdeps/x86_64/elf/start.S

......
_start:
	/* Clear the frame pointer.  The ABI suggests this be done, to mark
	   the outermost frame obviously.  */
	xorl %ebp, %ebp

	/* 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.	*/

	movq %rdx, %r9		/* Address of the shared library termination
				   function.  */
	popq %rsi		/* Pop the argument count.  */
	movq %rsp, %rdx		/* argv starts just at the current stack top.  */
	/* Align the stack to a 16 byte boundary to follow the ABI.  */
	andq  $~15, %rsp

	pushq %rax		/* Push garbage because we push 8 more bytes.  */

	/* Provide the highest stack address to the user code (for stacks
	   which grow downwards).  */
	pushq %rsp

#ifdef SHARED
	/* Pass address of our own entry points to .fini and .init.  */
	movq __libc_csu_fini@GOTPCREL(%rip), %r8
	movq __libc_csu_init@GOTPCREL(%rip), %rcx

	movq BP_SYM (main)@GOTPCREL(%rip), %rdi

	/* Call the user's main function, and exit with its value.
	   But let the libc call main.	  */
	call BP_SYM (__libc_start_main)@PLT
......

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值