gcc 编译过程

    平时我们使用gcc 编译C程序,我们通常只用 gcc  hello.c  -o  hello 之类的,顶多为了gdb调试再使用 -g 参数!

其实我们可以使用手动编译来了解整个gcc编译的过程!

我们使用最简单的Hello World 程序做示例:

#include "stdio.h"
int main()
{
    printf("Hello World\n");
    return  0;
}


1 、预处理(Pre-processing)

在该阶段,编译器将C源代码中的包含的头文件如stdio.h编译进来,用户可以使用gcc的选项”-E”进行查看。

 用法:       gcc -E hello.c -o  hello.i

作用:将hello.c预处理输出hello.i文件。

#ls
hello.c  
#gcc -E hello.c -o hello.i
#ls
hello.c  hello.i
使用vim 查看hello.i 可以看到 hello.i中包括很多很多头文件:

# 1 "hello.c"
# 1 "<命令行>"
# 1 "hello.c"
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
# 324 "/usr/include/features.h" 3 4
# 1 "/usr/include/i386-linux-gnu/bits/predefs.h" 1 3 4
# 325 "/usr/include/features.h" 2 3 4
# 357 "/usr/include/features.h" 3 4
……
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
# 940 "/usr/include/stdio.h" 3 4

# 2 "hello.c" 2
int main()
{
 printf("Hello World\n");
 return 0;
}


我们也可以使用 gcc -M hello.c 生成文件关联的信息。包含目标文件所依赖的所有源代码。        

#ls
hello.c  hello.i
#gcc -M hello.c 
hello.o: hello.c /usr/include/stdio.h /usr/include/features.h \
 /usr/include/i386-linux-gnu/bits/predefs.h \
 /usr/include/i386-linux-gnu/sys/cdefs.h \
 /usr/include/i386-linux-gnu/bits/wordsize.h \
 /usr/include/i386-linux-gnu/gnu/stubs.h \
 /usr/include/i386-linux-gnu/gnu/stubs-32.h \
 /usr/lib/gcc/i686-linux-gnu/4.7/include/stddef.h \
 /usr/include/i386-linux-gnu/bits/types.h \
 /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/libio.h \
 /usr/include/_G_config.h /usr/include/wchar.h \
 /usr/lib/gcc/i686-linux-gnu/4.7/include/stdarg.h \
 /usr/include/i386-linux-gnu/bits/stdio_lim.h \
 /usr/include/i386-linux-gnu/bits/sys_errlist.h
#

2 、编译阶段(Compiling)

第二步进行的是编译阶段,在这个阶段中,Gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc把代码翻译成汇编语言。用户可以使用”-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
 用法:       gcc -S --verbose-asm hello.i  -o hello.s
作用:将预处理输出文件hello.i汇编成hello.s文件。

#gcc -S --verbose-asm hello.i -o hello.s
#ls
hello.c  hello.i  hello.s

使用vim查看hello.s 文件:

 .file   "hello.c"
# GNU C (Ubuntu/Linaro 4.7.2-2ubuntu1) version 4.7.2 (i686-linux-gnu)
#   compiled by GNU C version 4.7.2, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# 传递的选项:  -fpreprocessed hello.i -mtune=generic -march=i686
# -auxbase-strip hello.s -fverbose-asm -fstack-protector
# 启用的选项:  -fasynchronous-unwind-tables -fauto-inc-dec
# -fbranch-count-reg -fcommon -fdebug-types-section
# -fdelete-null-pointer-checks -fdwarf2-cfi-asm -fearly-inlining
# -feliminate-unused-debug-types -ffunction-cse -fgcse-lm -fgnu-runtime
# -fident -finline-atomics -fira-share-save-slots -fira-share-spill-slots
# -fivopts -fkeep-static-consts -fleading-underscore -fmath-errno
# -fmerge-debug-strings -fmove-loop-invariants -fpcc-struct-return
# -fpeephole -fprefetch-loop-arrays -fsched-critical-path-heuristic
# -fsched-dep-count-heuristic -fsched-group-heuristic -fsched-interblock
# -fsched-last-insn-heuristic -fsched-rank-heuristic -fsched-spec
# -fsched-spec-insn-heuristic -fsched-stalled-insns-dep -fshow-column
# -fsigned-zeros -fsplit-ivs-in-unroller -fstack-protector
# -fstrict-volatile-bitfields -ftrapping-math -ftree-cselim -ftree-forwprop
# -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
# -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop -ftree-pta
# -ftree-reassoc -ftree-scev-cprop -ftree-slp-vectorize
# -ftree-vect-loop-version -funit-at-a-time -funwind-tables
# -fvect-cost-model -fverbose-asm -fzero-initialized-in-bss -m32 -m80387
# -m96bit-long-double -maccumulate-outgoing-args -malign-stringops
# -mfancy-math-387 -mfp-ret-in-387 -mglibc -mieee-fp -mno-red-zone
# -mno-sse4 -mpush-args -msahf -mtls-direct-seg-refs

    .section    .rodata
.LC0:
    .string "Hello World"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushl   %ebp    #
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp  #,
    .cfi_def_cfa_register 5
    andl    $-16, %esp  #,
    subl    $16, %esp   #,
    movl    $.LC0, (%esp)   #,
    call    puts    #
    movl    $0, %eax    #, D.1815
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret

3 、汇编阶段(Assembling)

汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码.
用法:
        gcc -c hello.s -o hello.o

作用:将汇编输出文件test.s编译输出test.o文件。

#ls
hello.c  hello.i  hello.s
#gcc -c hello.s -o hello.o
#ls
hello.c  hello.i  hello.o  hello.s

使用         file hello.o 查看hello.o文件信息:

#file hello.o 
hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
#


我们也可以使用objdump查看hello.o的汇编信息:         objdump -d hello.o

        

#objdump -d hello.o 

hello.o:     文件格式 elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	83 e4 f0             	and    $0xfffffff0,%esp
   6:	83 ec 10             	sub    $0x10,%esp
   9:	c7 04 24 00 00 00 00 	movl   $0x0,(%esp)
  10:	e8 fc ff ff ff       	call   11 <main+0x11>
  15:	b8 00 00 00 00       	mov    $0x0,%eax
  1a:	c9                   	leave  
  1b:	c3                   	ret    
#
这个和我们使用gdb调试时使用disassemble查看是一样的!

(gdb) disassemble 
Dump of assembler code for function main:
   0x0804840c <+0>:	push   %ebp
   0x0804840d <+1>:	mov    %esp,%ebp
   0x0804840f <+3>:	and    $0xfffffff0,%esp
   0x08048412 <+6>:	sub    $0x10,%esp
=> 0x08048415 <+9>:	movl   $0x80484c8,(%esp)
   0x0804841c <+16>:	call   0x80482f0 <puts@plt>
   0x08048421 <+21>:	mov    $0x0,%eax
   0x08048426 <+26>:	leave  
   0x08048427 <+27>:	ret    
End of assembler dump.
(gdb) 

4 、链接阶段(Link)


在成功编译之后,就进入了链接阶段。无选项链接。

用法:gcc -v hello.o -o hello

作用:将编译输出文件hello.o链接成最终可执行文件hello。

#gcc -v hello.o  -o hello
使用内建 specs。
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.7/lto-wrapper
目标:i686-linux-gnu
配置为:../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-2ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
线程模型:posix
gcc 版本 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1) 
COMPILER_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../../lib/:/lib/i386-linux-gnu/:/lib/../lib/:/usr/lib/i386-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/i686-linux-gnu/4.7/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'hello' '-mtune=generic' '-march=i686'
 /usr/lib/gcc/i686-linux-gnu/4.7/collect2 --sysroot=/ --build-id --no-add-needed --as-needed --eh-frame-hdr -m elf_i386 --hash-style=gnu -dynamic-linker /lib/ld-linux.so.2 -z relro -o hello /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crti.o /usr/lib/gcc/i686-linux-gnu/4.7/crtbegin.o -L/usr/lib/gcc/i686-linux-gnu/4.7 -L/usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu -L/usr/lib/gcc/i686-linux-gnu/4.7/../../../../lib -L/lib/i386-linux-gnu -L/lib/../lib -L/usr/lib/i386-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/i686-linux-gnu/4.7/../../.. hello.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i686-linux-gnu/4.7/crtend.o /usr/lib/gcc/i686-linux-gnu/4.7/../../../i386-linux-gnu/crtn.o
#

我们可以使用 nm hello 查看使用的符号信息

#nm hello
0804a020 B __bss_start
0804a020 b completed.6382
0804a018 D __data_start
0804a018 W data_start
08048350 t deregister_tm_clones
080483c0 t __do_global_dtors_aux
08049f0c t __do_global_dtors_aux_fini_array_entry
0804a01c D __dso_handle
08049f14 d _DYNAMIC
0804a020 D _edata
0804a024 B _end
080484a8 T _fini
080484c0 R _fp_hw
080483e0 t frame_dummy
08049f08 t __frame_dummy_init_array_entry
080485c8 r __FRAME_END__
0804a000 d _GLOBAL_OFFSET_TABLE_
         w __gmon_start__
080484a2 T __i686.get_pc_thunk.bx
080482b0 T _init
08049f0c t __init_array_end
08049f08 t __init_array_start
080484c4 R _IO_stdin_used
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
08049f10 d __JCR_END__
08049f10 d __JCR_LIST__
         w _Jv_RegisterClasses
080484a0 T __libc_csu_fini
08048430 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804840c T main
         U puts@@GLIBC_2.0
08048380 t register_tm_clones
08048320 T _start
0804a020 D __TMC_END__
#




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值