• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
            數據加載中……

            GNU binutils 使用小結


            GNU binutils
            是一組二進制工具集。包括:addr2line   ar   gprof   nm   objcopy   objdump   ranlib   size   strings   strip. 本文歸納他們的常用法。

            ar


                ar用于建立、修改、提取檔案文件(archive)archive是一個包含多個被包含文件的單一文件(也稱之為庫文件),其結構保證了可以從中檢索并得到原始的被包含文件(稱之為archive中的member)。member的原始文件內容、模式(權限)、時間戳、所有著和組等屬性都被保存在 archive中。member被提取后,他們的屬性被恢復到初始狀態。
               
                ar
            主要用于創建C庫文件

            創建靜態庫 
                (1)
            生成目標文件:  

            $ gcc -Wall -c file1.c file2.c file3.c

               
               
            不用指定生成.o文件名(默認生成file1.o, file2.o, file3.o)

                (2)
            .o目標文件創建靜態連接庫:
               

            $ ar rv libNAME.a file1.o file2.o file3.o

               
                ar
            生成了libNAME.a庫,并列出庫中的文件。
               
            r : flie1.o, file2,o, file3.o插入archive,如故原先archive中已經存在某文件,則先將該文件刪除。
               
            v : 顯示ar操作的附加信息



            創建動態庫(利用gcc,未用ar)

            (1)
            生成目標文件

            $ gcc -Wall -c -fpic file1.c file2.c file3.c


            -fpic:
            指定生成的.o目標文件可被重定址. picposition idependent code的縮寫: 位置無關代碼.

            (2)
            生成動態庫文件

            $ gcc -shared -o libNAME.so file1.o file2.o file3.o


            一般地, 連接器使用main()函數作為程序入口. 但在動態共享庫中沒有這樣的入口. 所以就要指定-shared選項來避免編譯器顯示出錯信息.

            實際上, 上述的兩條命令可以合并為下面這條:

            $ gcc -Wall -shared -fpic -o libNAME.so file1.c file2.c file3.c



            此后,將main函數所在的程序與libNAME.so連接
               
            至此,與動態庫連接的函數編譯成了一個可執行文件。貌似成功了,但還差最后一步。如果直接運行該程序,會給出這樣的錯誤信息:

            error while loading shared libraries: libhello.so:
            cannot open shared object file: No such file or directory


            這是因為與動態庫連接的程序在運行時,首先將該動態庫加載到內存中,而gcc默認加載動態庫文件所在目錄為/usr/local/lib, /usr/lib。剛才的程序雖然能編譯成功,但如果我們自己建立的動態庫沒有位于默認目錄中,則執行時會應為無法找到它而失敗。
              
            解決辦法:改變加載路徑對應的環境變量,然后再執行。
               

            export LD_LIBRARY_PATH=動態庫所在目錄:$LD_LIBRARY_PATH


            查看archive內容

            $ ar tv archiveNAME


            t :
            顯示archivemember的內容,若不指定member,則列出所有。
            v :
            t結合使用時,顯示member的詳細信息。

            要想進了解ar的詳細選項,參考aron-line manual


            nm


                nm用來列出目標文件中的符號,可以幫助程序員定位和分析執行程序和目標文件中的符號信息和它的屬性。
               
            如果沒有目標文件作為參數傳遞給nm, nm假定目標文件為a.out.
               
            這里用一個簡單的示例程序來介紹nm的用法:

            main.c:

            int main(int argc, char *argv[])
            {
              hello();
              bye();
              return 0;
            }


            hello.c:  

            void hello(void)
            {
              printf("hello!\n");
            }


            bye.c:
               

            void bye(void)
            {
              printf("good bye!\n");
            }


               
            運行下列命令:
               
            $ gcc -Wall -c main.c hello.c bye.c
                gcc
            生成main.o, hello.o, bye.o三個目標文件(這里沒有聲明函數原型,加了-Wall,gcc會給出警告)
                $ nm main.o hello.o bye.o

            結果顯示如下:  

            main.o:
                             U bye
                             U hello
            00000000 T main

            hello.o:
            00000000 T hello
                             U puts

            bye.o:
            00000000 T bye
                             U puts


               
            結合這些輸出結果,以及程序代碼,可以知道:
                對于main.o, byehello未被定義, main被定義了
               
            對于hello.o, hello被定義了, puts未被定義
               
            對于bye.o, bye被定義了,puts未被定義

            幾個值得注意的問題:
                (1)"
            目標文件".o文件, 庫文件, 最終的可執行文件
                .o  :
            編譯后的目標文件,即含有最終編譯出的機器碼,但它里面所引用的其他文件中函數的內存位置尚未定義.
                (2)
            如果用nm查看可執行文件, 輸出會比較多, 仔細研究輸出, 可以對nm用法有更清醒的認識.
                (3)
            在上述hello.c, bye.c, 調用的是printf(), nm輸出中顯示調用的是puts(), 說明最終程序實際調用的puts(), 如果令hello.cbye.c中的printf()使用格式化輸出,nm顯示調用printf(). ( : printf("%d", 1); )
               
               
            關于nm的參數選項,參考on-line manual


            objcopy


                objcopy可以將一種格式的目標文件轉化為另外一種格式的目標文件. 它使用GNU BFD庫進行讀/寫目標文件.使用BFD, objcopy就能將原格式的目標文件轉化為不同格式的目標文件.
                以我們在nm中使用的hello.o目標文件和hello可執行為例:

            $ file hello.o hello

              
                file
            命令用來判別文件類型, 輸出如下:
               
            hello.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
            hello:  ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.0, dynamically linked (uses shared libs), not stripped

               

               
            現在運行objcopy來改變hello的文件類型: 原先它是ELF格式的可執行程序, 現將它轉換為srec格式. srec格式文件是Motolora S-Record格式的文件, 主要用來在主機和目標機之間傳輸數據.
               

            $ objcopy -O srec hello hello_srec
            $ file hello.o hello


                file
            命令結果: hello_srec: Motorola S-Record; binary data in text format

               
            注意objcopy的格式, "-O"指定輸出文件類型; 輸入文件名和輸出文件名位于命令末尾. 關于objcopy命令的詳細選項, 參考on-line manual


            objdump


                objdump用來顯示目標文件的信息. 可以通過選項控制顯示那些特定信息. objdump一個最大的用處恐怕就是將C代碼反匯編了. 在嵌入式軟件開發過程中, 也可以用它查看執行文件或庫文件的信息.
               
            下面我們用上文提到的hello可執行文件和hello_srec可執行文件為例, 介紹objdump的簡單用法:
               

            $ objdump -f hello hello_srec


            輸出如下:
            hello:     file format elf32-i386
            architecture: i386, flags 0x00000112:
            EXEC_P, HAS_SYMS, D_PAGED
            start address 0x080482c0

            hello_srec:     file format srec
            architecture: UNKNOWN!, flags 0x00000000:
            start address 0x00000000080482c0

               

            -f : 顯示目標文件的頭文件概要信息.

            生成反匯編代碼:
               

            $ objdump -d hello.o


            顯示如下:
            hello.o:     file format elf32-i386

            Disassembly of section .text:

            00000000 <hello>:
               0:   55                      push   %ebp
               1:   89 e5                   mov    %esp,%ebp
               3:   83 ec 08                sub    $0x8,%esp
               6:   83 ec 0c                sub    $0xc,%esp
               9:   68 00 00 00 00          push   $0x0
               e:   e8 fc ff ff ff          call   f <hello+0xf>
              13:   83 c4 10                add    $0x10,%esp
              16:   c9                      leave
              17:   c3                      ret


                -d :
            顯示目標文件中機器指令使用的匯編語言. 只反匯編那些應該含有指令機器碼的節(顯示.text); 如果用-D, 則反匯編所有節的內容.
               
            關于objcopy命令的詳細選項, 參考on-line manual


            readelf


                readelf用來顯示ELF格式目標文件的信息.可通過參數選項來控制顯示哪些特定信息.(注意: readelf不支持顯示archive文檔, 也不支持64位的ELF文件).
               
            下面利用先前的hello可執行文件演示readelf的簡單用法:
               

            $ readelf -h hello


            ELF Header:
              Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
              Class:                                           ELF32
              Data:                                            2's complement, little endian
              Version:                                        1 (current)
              OS/ABI:                                          UNIX - System V
              ABI Version:                                   0
              Type:                                              EXEC (Executable file)
              Machine:                                        Intel 80386
              Version:                                          0x1
              Entry point address:                       0x80482c0
              Start of program headers:              52 (bytes into file)
              Start of section headers:                 3848 (bytes into file)
              Flags:                                               0x0
              Size of this header:                          52 (bytes)
              Size of program headers:                32 (bytes)
              Number of program headers:          7
              Size of section headers:                  40 (bytes)
              Number of section headers:            34
              Section header string table index:   31

            注意: readelf只能用于ELF格式目標文件, 且選項中至少要指定一個(V, H)的選項!


            gprof


                gprof被用來測量程序的性能. 它記錄每個函數被調用的次數以及相應的執行時間. 這樣就能鎖定程序執行時花費時間最多的部分, 對程序的優化就可集中于對它們的優化.
               
               
            用一個簡單的數值計算程序來掩飾gprof的用法:

            collatz.c:

            #include <stdio.h>
            /* Computes the length of Collatz sequences */
            unsigned int step (unsigned int x)
            {
                 if (x % 2 == 0)
                 {
                  return (x / 2);
                 }
                 else
                 {
                  return (3 * x + 1);
                 }
            }

            unsigned int nseq (unsigned int x0)
            {
                 unsigned int i = 1, x;
                 if (x0 == 1 || x0 == 0)
                  return i;
                 x = step (x0);
                 while (x != 1 && x != 0)
                 {
                  x = step (x);
                  i++;
                 }
                 return i;
            }

            int main (void)
            {
                 unsigned int i, m = 0, im = 0;
                 for (i = 1; i < 500000; i++)
                 {
                  unsigned int k = nseq (i);
                  if (k > m)
                  {
                       m = k;
                       im = i;
                       printf ("sequence length = %u for %u\n", m, im);
                  }
                 }
                 return 0;
            }


               
            先將collatz.c編譯成目標文件collatz.o gcc通過 -pg選項來打開gprof支持:
               

            $ gcc -Wall -c -pg collatz.c

             

            $ gcc -Wall -pg -o collatz collatz.o


               
            注意:兩條命令都要加 "-pg"選項。前一條命令生成collatz.o目標文件。后一條命令生成可執行文件,該可執行文件中包含了記錄函數執行時間的指令。
               
            生成collatz可執行文件后,現執行它,結果與一般程序的執行無疑。但此時在PWD目錄生成一個名為"gmon.out"的文件,gprof通過它來分析程序的執行。
               
            如果不現執行程序,而直接用gprof來分析它,會提示“gmon.out: No such file or directory”

                gprof
            用法:
               

            $ gprof ./collatz

             

             

            posted on 2007-08-28 15:59 Normandy 閱讀(1027) 評論(0)  編輯 收藏 引用 所屬分類: Toolkit

            久久99亚洲综合精品首页| 久久er热视频在这里精品| 久久久精品国产亚洲成人满18免费网站| 97久久超碰成人精品网站| 日本精品久久久中文字幕| 久久这里有精品视频| 伊人久久精品无码二区麻豆| 久久久无码精品亚洲日韩蜜臀浪潮| 久久亚洲国产成人精品性色| Xx性欧美肥妇精品久久久久久 | 久久婷婷五月综合色高清| 久久精品www| 精品久久人人爽天天玩人人妻| 久久久精品午夜免费不卡| 亚洲欧美久久久久9999| 99久久精品国产高清一区二区| 午夜福利91久久福利| 88久久精品无码一区二区毛片 | 久久ww精品w免费人成| 亚洲精品NV久久久久久久久久| 久久久国产精品亚洲一区 | 性做久久久久久久| 久久伊人亚洲AV无码网站| AV无码久久久久不卡网站下载| 日韩美女18网站久久精品| 久久精品国产秦先生| 人妻精品久久无码专区精东影业| 久久久久亚洲AV成人网人人网站| 国产精品99久久99久久久| 久久婷婷五月综合97色| 亚洲va国产va天堂va久久| 国产精品久久久久久久app| 久久久久久久综合综合狠狠| 久久夜色tv网站| 国产精品久久成人影院| 国产精品美女久久久m| 久久九九亚洲精品| 国产成人99久久亚洲综合精品| 久久夜色精品国产亚洲| 久久久久亚洲av成人无码电影| 久久男人中文字幕资源站|