GCC的編譯流程詳解

來源:互聯網
上載者:User

 

 

    一、首先,先對Linux下C語言開發的流程有個大體的瞭解。簡單的說,就是:

    1、編寫C程式原始碼*.c    2、預先處理(Pre-Processing)    3、編譯(Compiling)    4、彙編(Assembling)-->產生目標代碼*.o    5、連結(Linking)-->產生可執行檔    6、調試    其中,第一步工作用編輯器來實現,用Emacs、Vi(m)都可以。我現在習慣用Vim。在RedHat9.0中,Vim版本為6.1,系統採用alias用vi作為vim的別名,因此在shell提示符下輸入vi實際上使用的編輯器vim(Vi IMproved)。你可以使用which查看一下:[armlinux@lqm program]$ which vi
alias vi='vim'
        /usr/bin/vim    除去第6步的工作由GDB之類的調試器來完成,中間的四步工作都是由GCC來完成的。    二、下面大體瞭解一下GCC。---------------------------------------標準
  • ANSI C:這一標準是 ANSI(美國國家標準局)於 1989 年制定的 C 語言標準。後來被 ISO(國際標準組織)接受為標準,因此也稱為 ISO C。
    ANSI C 的目標是為各種作業系統上的 C 程式提供可移植性保證,而不僅僅限於 UNIX。 該標準不僅定義了 C 程式設計語言的語發和語義,而且還定義了一個標準庫。這個庫可以根據 標頭檔劃分為 15 個部分,其中包括:字元類型 (<ctype.h>)、錯誤碼 (<errno.h>)、 浮點常數 (<float.h>)、數學常數 (<math.h>)、標準定義 (<stddef.h>)、 標準 I/O (<stdio.h>)、工具函數 (<stdlib.h>)、字串操作 (<string.h>)、 時間和日期 (<time.h>)、可變參數表 (<stdarg.h>)、訊號 (<signal.h>)、 非局部跳轉 (<setjmp.h>)、本地資訊 (<local.h>)、程式斷言 (<assert.h>) 等等。
  • POSIX:該標準最初由 IEEE 開發的標準族,部分已經被 ISO 接受為國際標準。該標準的具體內容 見 1.1.3。POSIX.1 和 POSIX.2 分別定義了 POSIX 相容作業系統的 C 語言系統介面 以及 shell 和工具標準。這兩個標準是通常提到的標準。
  • SVID:System V 的介面描述。System V 介面描述(SVID)是描述 AT&&;T Unix System V 操作 系統的文檔,是對 POSIX 標準的擴充超集。
  • XPG:X/Open 可移植性指南。X/Open 可移植性指南(由 X/Open Company, Ltd.出版), 是比 POSIX 更為一般的標準。X/Open 擁有 Unix 的著作權,而 XPG 則指定成為 Unix 作業系統必須滿足的要求。---------------------------------------    GCC是GNU CC的簡稱,它是符合上述ANSI C標準的編譯系統,能夠編譯C、C++、Object C等語言編寫的程式。GCC還是一個交叉平台編譯器,能夠在當前CPU平台為多種不同架構的硬體平台開發軟體,因此適合嵌入式領域的開發編譯。GCC所支援的尾碼名的解釋.c C原始程式.C/.cc/.cxx C++原始程式.m Object C原始程式.i 已經過預先處理的C原始程式.ii 已經過預先處理的C++原始程式.s/.S 組合語言原始程式.h 預先處理檔案(標頭檔).o 目標檔案.a/.so 編譯後的庫檔案    三、詳解GCC編譯流程    使用vi編寫源檔案hello.c。#include <stdio.h>int main()
    {
            int i;
            for(i=1;i<9;i++)
                    printf("Hello World %d times!/n",i);
            return 0;
    }    1、預先處理階段     該階段的作用是把預先處理檔案,也就是標頭檔編譯進來。在此例中,就是要把stdio.h編譯進來。可使用-E選項查看,作用是讓gcc在預先處理結束後停止編譯過程。[armlinux@lqm program]$ gcc -E hello.c -o hello.i[armlinux@lqm program]$ cat hello.i | less# 1 "hello.c"
    # 1 "<built-in>"
    # 1 "<command line>"
    # 1 "hello.c"
    # 1 "/usr/include/stdio.h" 1 3
    # 28 "/usr/include/stdio.h" 3
    # 1 "/usr/include/features.h" 1 3
    # 291 "/usr/include/features.h" 3
    # 1 "/usr/include/sys/cdefs.h" 1 3
    # 292 "/usr/include/features.h" 2 3
    # 314 "/usr/include/features.h" 3
    # 1 "/usr/include/gnu/stubs.h" 1 3
    # 315 "/usr/include/features.h" 2 3
    # 29 "/usr/include/stdio.h" 2 3...extern void funlockfile (FILE *__stream) ;
    # 679 "/usr/include/stdio.h" 3# 2 "hello.c" 2int main()
    {
            int i;
            for(i=1;i<9;i++)
                    printf("Hello World %d times!/n",i);
            return 0;
    }    由此可見,stdio.h的內容已經插入到hello.c中,即GCC完成了預先處理過程。    2、編譯階段    GCC的工作是首先檢查代碼的規範性、是否有語法錯誤,以確定代碼實際要做的工作。檢查無誤後,將之翻譯為組合語言。可用-S來查看,即只編譯而不進入彙編階段。[armlinux@lqm program]$ gcc -S hello.i -o hello.s[armlinux@lqm program]$ cat hello.s        .file   "hello.c"
            .section        .rodata
    .LC0:
            .string "Hello World %d times!/n"
            .text
    .globl main
            .type   main,@function
    main:
            pushl   %ebp
            movl    %esp, %ebp
            subl    $8, %esp
            andl    $-16, %esp
            movl    $0, %eax
            subl    %eax, %esp
            movl    $1, -4(%ebp)
    .L2:
            cmpl    $8, -4(%ebp)
            jle     .L5
            jmp     .L3
    .L5:
            subl    $8, %esp
            pushl   -4(%ebp)
            pushl   $.LC0
            call    printf
            addl    $16, %esp
            leal    -4(%ebp), %eax
            incl    (%eax)
            jmp     .L2
    .L3:
            movl    $0, %eax
            leave
            ret
    .Lfe1:
            .size   main,.Lfe1-main
            .ident "GCC: (GNU) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"    3、彙編階段    GCC把編譯產生的.s檔案轉換為目標檔案.o。這時使用-c選項就可以看到彙編代碼已經轉換成.o的目標代碼了。[armlinux@lqm program]$ gcc -c hello.s -o hello.o    4、連結階段    成功編譯之後,就進入了連結階段。這裡首先要明白“庫”的概念。這個程式中沒有“printf”的函數實現,且在預先處理階段包含進來的“stdio.h”中只有該函數的聲明,而沒有定義函數的實現。如何?“printf”?答案是:系統把這些函數的實現都做到名位libc.so.6的庫檔案裡了,沒有特別指定時,GCC會到預設的搜尋路徑“/usr/lib”下進行尋找。也就是連結到libc.so.6庫函數中去來實現函數“printf”,這就是連結的作用。    在RedHat 9下的函數庫如下:    /lib:系統必備共用庫    /usr/lib:標準共用庫和靜態庫    /usr/X11R6/lib:X11R6的函數庫    /usr/local/lib:本地函數庫    標頭檔:    /usr/include:系統標頭檔    /usr/local/include:本地標頭檔    在/etc/ld.so.conf中包含著共用庫的搜尋位置。我的libc.so.6在/lib下面,它是一個link,指向libc-2.3.2.so。這是因為我用的C庫--glibc版本是2.3.2。    函數庫一般可分為靜態庫和動態庫兩種。靜態庫是指連結時把庫檔案的代碼全部加到可執行檔中,因此產生的檔案比較大,但是在運行時就不再需要庫檔案了。其尾碼名一般為“.a”。動態庫在連結時並沒有把庫檔案的代碼加入到可執行檔中,而是在程式執行時由運行時連結檔案載入庫,這樣可以節省系統的開銷。動態庫一般尾碼名為“.so”。GCC在編譯時間預設使用動態庫。[armlinux@lqm program]$ gcc hello.o -o hello1
    [armlinux@lqm program]$ ls -l hello1
    -rwxrwxr-x    1 armlinux armlinux    11582 8月 28 17:42 hello1
    [armlinux@lqm program]$ file hello1
    hello1: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not sd
    [armlinux@lqm program]$ gcc -static hello.o -o hello2
    [armlinux@lqm program]$ ls -l hello2
    -rwxrwxr-x    1 armlinux armlinux   423442 8月 28 17:43 hello2
    [armlinux@lqm program]$ file hello2
    hello2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, statically linked, not stripped[armlinux@lqm program]$ ./hello1
    Hello World 1 times!
    Hello World 2 times!
    Hello World 3 times!
    Hello World 4 times!
    Hello World 5 times!
    Hello World 6 times!
    Hello World 7 times!
    Hello World 8 times!
    [armlinux@lqm program]$ ./hello2
    Hello World 1 times!
    Hello World 2 times!
    Hello World 3 times!
    Hello World 4 times!
    Hello World 5 times!
    Hello World 6 times!
    Hello World 7 times!
    Hello World 8 times!    hello2是靜態編譯,大小423442,是動態編譯的36.56倍。利用file可以看出此檔案statically linked,還是dynamically linked (uses shared libs)。    至此,GCC的整個編譯連結過程就完成了。
  • 轉自http://hi.baidu.com/caibaihui/blog/item/01abdc8b7af0a317c9fc7ac4.html

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.