GCC——C程序是如何编译成的

转载 2011年01月18日 15:57:00
摘要:
    在windows环境,我们有集成开发环境(IDE),使得我们对编译器了解的很少。当我们专向linux时需要在命令行下编译自己的程序需要对编译器的 命令行参数比较熟悉。而如果是做嵌入开发构建自己的操作系统时失去了系统平台,需要我们对编译的过程以及可执行文件的内部结构有所了解。本文讲述了如何编 译可执行文件、静态库、动态库,如何优化编译器,如何编译无操作系统环境下的程序(自己的OS)等。

1.分析普通的helloworld程序
    先书写一下一个简单的helloworld程序如下:
/* hello.c */
int main(int argc, char * argv[])
{
    return 0
}
    编译程序:
gcc -o hello hello.c
    等价的编译方法:
gcc -c hello.c
gcc -o hello.my -nostartfiles hello./usr/lib/crt1./usr/lib/crti./usr/lib/crtn.o
    我在redflag workstation 5.0版本下用3.4.3版本GCC编译器编译出来的大小都是3589字节,并且用diff命令比较为相同的文件。由此证明gcc在编译并链接 hello.c文件时先将hello.c编译成hello.o,然后将它与crt1.o、crti.o、crtn.o链接在一起。

    如果要写一个没有main函数的程序,就需要自己实现crt1.o。程序入口为符号“_start”处。代码如下:
/* nomain.c */
void _start(void)
{
    _exit(0);
}
gcc -o nomain -nostartfiles hello.c

2.编译和使用库
    除了直接编译代码外还会使用到函数库。库有静态库和动态库之分。静态库是以.a结尾的文件,例如:libXXX.a;动态库是以.so结尾的文件,例如: libXXX.so。XXX之后或者.so和.a之后会跟版本号,例如:libc-2.3.4.so,或者libuuid.so.1.2。
    加入函数库的代码如下:
/* test.h */
int test1 (void);

/* test.c */
#include <stdio.h>
#include "libtest.h"

int test1 (void)
{
    printf("test1 function is called./n");
    return 0;
}
    当要编译成静态库的时候使用如下命令生成libtest.a:
gcc -test.c
ar -r libtest.test.o
    当要编译成动态链接库的时候使用如下命令生成libtest.so
gcc --fpic test.c
gcc -shared test.-o libtest.so

gcc -fpic -shared test.-o libtest.so
    当需要调用该库时使用如下代码。
/* calllib.c */
#include "test.h"

int main (int argc, char * argv[])
{
    test1();
}
    按如下方式编译:
gcc -o calllib.static calllib.c libtest.a

gcc -o calllib.dynamic calllib.c libtest.so

gcc -o calllib calllib.-ltest
    前提是libtest.a或libtest.so在当前编译的目录。
    使用ldd显示calllib.static依赖的库只有libc和ld-linux,但calllib.dynamic就多了一个libtest.so。


3.库文件和头文件
    在程序中,使用#include <stdio.h>类似的头文件stdio.h在编译器的头文件路径中,#include "abc.h"中的stdio.h文件则应该在当前目录。通过对编译器指定参数-I<PATH>来指定头文件所在目录,可以用 #include <>来引用。例如:gcc -I./include hello.c,将从当前目录下的include目录下去寻找头文件。
    同理,程序中调用的库函数在编译时也需要指定路径,同时指定库。使用-L<PATH>参数指定库文件的目录,-l<FILE>指定包含的库文件。例如,要使用libXXX.so库,参数为-lXXX。
    一般一个库编译完成后有库文件和头文件。如果要使用这个库,可以将库文件目录和头文件目录分别用-I和-L参数指定,也可以将他们拷贝到编译器的include和lib目录下。


4.缩小程序体积
    代码如下:
/* nomain.c */
void _start(void)
{
    asm("movl , eax/n"
        "movl {fckeditor}, ebx/n"
        "int {fckeditor}x80"
    );
}
使用如下方法能使可执行文件体积最小(手工方法除外)。
gcc -o nomain --O3 nomain.c
objcopy -.comment -.data
    由此得到可执行文件的体积为352字节。


    GCC能编译出2种格式的可执行体:a.out格式、elf格式。其中.o目标文件、.a静态库文件

Appendix.1 常用命令
ldd:显示可执行文件或者库文件依赖的库文件。
objdump:显示elf可执行文件的内部信息。
    -h:显示
    -t:显示符号信息
    -T:显示动态符号信息。(例如引用动态链接库中的函数名称)
    -r:显示重定位入口信息。
    -R:显示动态重定位入口信息。(例如:动态链接库中的变量或者函数地址)
    -s:显示所有section内容。
    -S:反汇编代码段。
objcopy:copy elf文件内容
    -R:删除某个section
    -j:仅仅复制指定的section

GCC——C程序是如何编译成的

摘要:    在windows环境,我们有集成开发环境(IDE),使得我们对编译器了解的很少。当我们专向linux时需要在命令行下编译自己的程序需要对编译器的 命令行参数比较熟悉。而如果是做嵌入开发构...
  • ljx0305
  • ljx0305
  • 2008年12月18日 11:30
  • 1240

GCC从源文件如何蜕变成可执行文件

GCC的编译过程 一、预处理: 对源程序中的伪指令(即以#开头的指令)和特殊符号进行处理的过程,即进行头文件的展开,宏替换,条件编译 如以下的一段简单程序: #include int main(...
  • zscfa
  • zscfa
  • 2016年07月06日 20:38
  • 510

GCC——C程序是如何编译成的[转]

GCC——C程序是如何编译成的[转]作者:deven摘要:   在windows环境,我们有集成开发环境(IDE),使得我们对编译器了解的很少。当我们专向linux时需要在命令行下编译自己的程序需要对...
  • trunk0813
  • trunk0813
  • 2008年11月19日 13:24
  • 451

GCC—C程序是如何编译成的 -windows

http://unix-cd.com/vc/www/23/2007-07/5713.html 摘要:     在windows环境,我们有集成开发环境(IDE),使得我们对编译器了解的很少。当...
  • larryliuqing
  • larryliuqing
  • 2012年04月06日 12:19
  • 717

c程序是如何编译成的

1.分析普通的helloworld程序    先书写一下一个简单的helloworld程序如下:/* hello.c */int main(int argc, char * argv[]){    r...
  • Julia_li_2007
  • Julia_li_2007
  • 2008年12月15日 13:39
  • 602

Linux内核分析(-)——反编译C代码

翁高剑  原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 初学网易云课堂的Linu...
  • Polly_Weng
  • Polly_Weng
  • 2015年03月08日 22:08
  • 1561

Linux下c和cuda混合编译,并生成动态链接库.so和使用

梗概如果要生成动态链接库,就需要把源码,无论是.c .cpp .cu还是其他的语言写的程序,都通过编译器变成.o文件,之后把相应的.o文件进行链接成为.so动态链接库。这样就可以直接调用其中的函数了。...
  • u012816621
  • u012816621
  • 2016年08月27日 14:27
  • 3437

[编译环境][gcc]编译16位程序

使用gcc编写16位程序
  • cloudblaze
  • cloudblaze
  • 2015年12月13日 11:00
  • 1283

使用C++(I386+)编译一个纯二进制文件

环境搭建设在目前,很少有关于这方面太多的资料。因此这也是我下决心来写一些东西的原因,希望这篇文章能对大家有所帮助。在读该篇文章前,你必须有一定的基础。否则,在阅读时会有很大困难,首先你要了解汇编语言及...
  • hacking
  • hacking
  • 2003年10月02日 01:18
  • 843

c语言的cgi编译全过程

c语言的cgi编译全过程 1,在Redhat9下建立hello.c文件 ------------- #include #include main() { prin...
  • u010402372
  • u010402372
  • 2014年05月02日 17:43
  • 2116
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:GCC——C程序是如何编译成的
举报原因:
原因补充:

(最多只允许输入30个字)