《C编译原理》ubuntu下helloword编译连接过程分析
2013-05-13 14:13
357 查看
C可执行文件的生成包括如下步骤:预处理、编译、链接;下边分析编译和链接。
一、源程序
vi hello.c
二、编译及连接
gcc -v hello.c -o hello
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.*
下面看gcc4.4.6中crt1.o的源码:
glibc-2.14.1/sysdeps/x86_64/elf/start.S
一、源程序
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 ......
相关文章推荐
- 代码的编译、连接与执行过程分析
- 对编译连接过程的近距离分析
- Arm Linux交叉编译和连接过程分析(1)
- Arm Linux交叉编译和连接过程分析(2)
- linux连接库编译过程分析
- Ubuntu内核编译简单过程
- U-boot分析第1章------------------Makefile(编译过程)
- TCP全连接队列和半连接队列已满之后的连接建立过程抓包分析
- Go-ethereum编译过程分析(一)
- 在ubuntu中编译Apue过程中碰到的问题
- Android应用程序资源的编译和打包过程分析
- 用make-kpkg简化Ubuntu系统的内核编译过程
- LSD-SLAM 编译过程(Ubuntu 14.04 + ROS Indigo)
- WebRTC在Ubuntu下的编译过程
- Android应用程序资源的编译和打包过程分析
- 整理在ubuntu重装之后配置过程(6G内存,修改网卡物理地址,修改hosts,codeblocks,eclipse,jdk,配置eclipse编译python)
- uboot编译配置过程分析
- 编译原理(八) 算符优先分析法(分析过程的算法和C++实现)
- Ubuntu 14.04 LTS 下 android 2.3.5 源码编译过程
- Ubuntu上交叉编译valgrind for Android 4.4的过程与注意事项