结合“hello world”探讨gcc编译程序的过程
结合“hello world”探讨gcc编译程序的过程
1. gcc简介
gcc/g++是GNU工程的C和C++编译器。都要用四个步骤中的一个或多个处理输入文件。
· 预处理(preprocessing)
· 编译(compilation)
· 汇编(assembly)
· 连接(linking)
源文件后缀名标识源文件的语言,但是对编译器来说,后缀名控制着缺省设定。
gcc命令的一般格式为:gcc [选项] 要编译的文件 [选项] [目标文件]
gcc的详细内容,可参考gcc manual。
2. gcc的输出选项
gcc输出选项,-o后指定输出文件名,gcc解释如下。
`-o FILE' Place output in file FILE. This applies regardless to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler file or preprocessed C code. If `-o' is not specified, the default is to put an executable file in `a.out', the object file for `SOURCE.SUFFIX' in `SOURCE.o', its assembler file in `SOURCE.s', a precompiled header file in `SOURCE.SUFFIX.gch', and all preprocessed C source on standard output.
|
指定输出文件为FILE,该选项不考虑GCC产生什么输出,无论是可执行文件、目标文件、汇编文件还是预处理后的C代码。 如果没有使用`-o'选项,默认的输出结果是:可执行文件为a.out,source.suffix的目标文件是source.o,汇编文件是source.s,而预处理后的C代码送往标准输出。 |
3. "hello wolrd"的处理过程
本文以"hello world"程序,探讨GCC编译程序的过程。
hello.c文件内容如下。
#include <stdio.h>
int main(int argc, char **argv) { printf("Hello World! via %x\n", printf); return 0; } |
3.1 预处理(preprocessing)
在该阶段,编译器将C源代码中的包含的头文件如stdio.h编译进来,可以使用gcc的选项”-E”进行查看预处理结果。
Gcc manual中对-E选项的解释如下。
`-E' Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output. Input files which don't require preprocessing are ignored. |
预处理后停止,不进行编译。预处理后的代码送往标准输出。GCC忽略任何不需要预处理的输入文件。 |
格式:gcc -E hello.c -o hello.i
作用:对hello.c进行预处理输出为hello.i文件
Hello.c被预处理后的hello.i文件。
# 1 "hello.c" # 1 "<built-in>" # 1 "<command line>" # 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 # 335 "/usr/include/features.h" 3 4 # 1 "/usr/include/sys/cdefs.h" 1 3 4 # 360 "/usr/include/sys/cdefs.h" 3 4 # 1 "/usr/include/bits/wordsize.h" 1 3 4 # 361 "/usr/include/sys/cdefs.h" 2 3 4 # 336 "/usr/include/features.h" 2 3 4 # 359 "/usr/include/features.h" 3 4 # 1 "/usr/include/gnu/stubs.h" 1 3 4
# 1 "/usr/include/bits/wordsize.h" 1 3 4 # 5 "/usr/include/gnu/stubs.h" 2 3 4
# 1 "/usr/include/gnu/stubs-32.h" 1 3 4 # 8 "/usr/include/gnu/stubs.h" 2 3 4 # 360 "/usr/include/features.h" 2 3 4 # 29 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/lib/gcc/i386-RedHat-linux/4.1.2/include/stddef.h" 1 3 4 # 214 "/usr/lib/gcc/i386-redhat-linux/4.1.2/include/stddef.h" 3 4 typedef unsigned int size_t; # 35 "/usr/include/stdio.h" 2 3 4
# 1 "/usr/include/bits/types.h" 1 3 4 # 28 "/usr/include/bits/types.h" 3 4 # 1 "/usr/include/bits/wordsize.h" 1 3 4 # 29 "/usr/include/bits/types.h" 2 3 4
typedef unsigned char __u_char; typedef unsigned short int __u_short; typedef unsigned int __u_int; typedef unsigned long int __u_long;
typedef signed char __int8_t; typedef unsigned char __uint8_t; typedef signed short int __int16_t; typedef unsigned short int __uint16_t; typedef signed int __int32_t; typedef unsigned int __uint32_t;
__extension__ typedef signed long long int __int64_t; __extension__ typedef unsigned long long int __uint64_t;
__extension__ typedef long long int __quad_t; __extension__ typedef unsigned long long int __u_quad_t; # 131 "/usr/include/bits/types.h" 3 4 # 1 "/usr/include/bits/typesizes.h" 1 3 4 # 132 "/usr/include/bits/types.h" 2 3 4
... |
3.2 编译(compilation)
在这个阶段中,Gcc首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,Gcc把代码翻译成汇编语言。可以使用”-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
Gcc manual中对-S选项的解释如下。
`-S' Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified. By default, the assembler file name for a source file is made by replacing the suffix `.c', `.i', etc., with `.s'. Input files that don't require compilation are ignored. |
编译后即停止,不进行汇编。对于每个输入的非汇编语言文件,输出文件是汇编语言文件。 缺省情况下,GCC通过用`.o'替换源文件名后缀`.c',`.i'等以产生目标文件名。可以使用-o选项指定选择其他名字。GCC忽略任何不需要编译的输入文件。 |
格式:gcc –S hello.i –o hello.s
作用:将预处理输出文件hello.i汇编成hello.s文件
Hello.i被汇编后的hello.s文件。
.file "hello.c" .section .rodata .LC0: .string "Hello World! via %x\n" .text .globl main .type main, @function main: leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $20, %esp movl $printf, 4(%esp) movl $.LC0, (%esp) call printf movl $0, %eax addl $20, %esp popl %ecx popl %ebp leal -4(%ecx), %esp ret .size main, .-main .ident "GCC: (GNU) 4.1.2 20070925 (Red Hat 4.1.2-33)" .section .note.GNU-stack,"",@progbits |
|
评论暂时关闭