• <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>

            elva

            COFF文件的格式

            COFF文件的格式

            COFF格式
                 COFF – 通用對象文件格式(Common Object File Format),是一種很流行的對象文件格式(注意:這里不說它是“目標(biāo)”文件,是為了和編譯器產(chǎn)生的目標(biāo)文件(*.o/*.obj)相區(qū)別,因?yàn)檫@種格式不只用于目標(biāo)文件,庫文件、可執(zhí)行文件也經(jīng)常是這種格式)。大家可能會經(jīng)常使用VC吧?它所產(chǎn)生的目標(biāo)文件(*.obj)就是這種格式。其它的編譯器,如GCC(GNU Compiler Collection)、ICL(Intel C/C++ Compiler)、VectorC,也使用這種格式的目標(biāo)文件。不僅僅是C/C++,很多其它語言也使用這種格式的對象文件。統(tǒng)一格式的目標(biāo)文件為混合語言編程帶來了極大的方便。
                當(dāng)然,并不是只有這一種對象文件格式。常用格式的還有OMF-對象模型文件(Object Module File)以及ELF-可執(zhí)行及連接文件格式(Executable and Linking Format)。OMF是一大群IT巨頭在n年制定的一種格式,在Windows平臺上很常見。大家喜歡的Borland公司現(xiàn)在使用的目標(biāo)文件就是這種格式。MS和Intel在n年前用的也是這種格式,現(xiàn)在都改投異側(cè),用COFF格式了。ELF格式在非Windows平臺上使用得比較多,在Windows平臺基本上沒見過。做為程序員,很有必要認(rèn)識一下這些你經(jīng)常打交道的家伙!不過這次讓我介紹COFF先!     COFF的文件結(jié)構(gòu)
                讓我們先來看一下COFF文件的整體結(jié)構(gòu),看看它到底長得什么樣!

            File Header

            Optional Header

            Section Header 1

            ......

            Section Header n

            Section Data

            Relocation Directives

            Line Numbers

            Symbol Table

            String Table

            如左圖:
            COFF文件一共有8種數(shù)據(jù),自上而下分別為:
            1. 文件頭(File Header)
            2. 可選頭(Optional Header)
            3. 段落頭(Section Header)
            4. 段落數(shù)據(jù)(Section Data)
            5. 重定位表(Relocation Directives)
            6. 行號表(Line Numbers)
            7. 符號表(Symbol Table)
            8. 字符串表(String Table)
                其中,除了段落頭可以有多個節(jié)(因?yàn)榭梢杂卸鄠€段落)以外,其它的所有類型的節(jié)最多只能有一個。
                文件頭:顧名思義,它就是COFF文件的頭,它用來保存COFF文件的基本信息,如文件標(biāo)識,各個表的位置等等。
                可選頭:再顧名思義,它也是一個頭,還是可選的,而且可有可無。在目標(biāo)文件中,基本上都沒有這個頭;但在其它的文件中(如:可執(zhí)行文件)這個段用來保存在文件頭中沒有描述到的信息。
                段落頭:又顧……(不顧了,再顧有人要打我了J),這個頭(怎么這么多的頭啊?!)是用來描述段落信息的,每個段落都有一個段落頭來描述。段落的數(shù)目在文件頭中會指出。
                段落數(shù)據(jù):這通常是COFF文件中最大的數(shù)據(jù)段,每個段落真正的數(shù)據(jù)就保存在這個位置。至于怎么區(qū)分這些數(shù)據(jù)是哪個段落的,不要問我,去問段落頭。
                重定位表:這個表通常只存在于目標(biāo)文件中,它用來描述COFF文件中符號的重定位信息。至于為什么要重定位,請回家看看你的操作系統(tǒng)的書籍。
                符號表:這個表用來保存COFF文件中所用到的所有符號的信息,連接多個COFF文件時(shí),這個表幫助我們重定位符號。調(diào)試程序時(shí)也要用到它。
                字符串表:不用我說,大家也知道它用來保存字符串的。可是字符串保存給誰看呢?不知道了吧!?問我啊!J符號表是以記錄的形式來描述符號信息的,但它只為符號名稱留置了8個字符的空間,早期的小程序還將就能行,可在現(xiàn)在的程序中,一個符號名動不動就數(shù)十個字符,8個字符怎么能夠?沒辦法,只好把這些名稱存在字符串表中。而符號表中只記錄這些字符串的位置。
                文件的結(jié)構(gòu)大體上就是這樣了。長得是丑了點(diǎn),不過還算它的設(shè)計(jì)者有點(diǎn)遠(yuǎn)見。可擴(kuò)充性設(shè)計(jì)得不錯,以致于沿用至今。了解了文件的整體結(jié)構(gòu),現(xiàn)在讓我們來逐個段落分析它。

                文件頭
                文件頭,自然是從文件的0偏移處開始,它的結(jié)構(gòu)很簡單。用C的結(jié)構(gòu)描述如下:
            typedef struct {
              unsigned short usMagic;  // 魔法數(shù)字
              unsigned short usNumSec;  // 段落(Section)數(shù)
              unsigned long  ulTime;  // 時(shí)間戳
              unsigned long  ulSymbolOffset;  // 符號表偏移
              unsigned long  ulNumSymbol;  // 符號數(shù)
              unsigned short usOptHdrSZ;  // 可選頭長度
              unsigned short usFlags;  // 文件標(biāo)記
            } FILEHDR;
                結(jié)構(gòu)中usMagic成員是一個魔法數(shù)字(Magic Number),在I386平臺上的COFF文件中它的值為0x014c。如果COFF文件頭中魔法數(shù)字不為0x014c,那就不用看了,這不是一個I386平臺的COFF文件。其實(shí)這就是一個平臺標(biāo)識。
                第二個成員usNumSec是一個無符號短整型,它用來描述段落的數(shù)量。段落頭(Section Header)的數(shù)目就是它。
                ulTime成員是一個時(shí)間戳,它用來描述COFF文件的建立時(shí)間。當(dāng)COFF文件為一個可執(zhí)行文件時(shí),這個時(shí)間戳經(jīng)常用來當(dāng)做一個加密用的比對標(biāo)識。
                ulSymbolOffset是符號表在文件中的偏移量,這是一個絕對偏移量,要從文件頭開始計(jì)數(shù)。在COFF文件的其它節(jié)中,也存在這種偏移量,它們都是絕對偏移量。
                ulNumSymbol成員給出了符號表中符號記錄的數(shù)量。
                usOptHdrSZ是可選頭的長度,通常它為0。而可選頭的類型也是從這個長度得知的,針對不同的長度,我們就要選擇不同的處理方式。
                usFlag是COFF文件的屬性標(biāo)記,它標(biāo)識了COFF文件的類型,COFF文件中所保存的數(shù)據(jù)等等信息。
                其值如下:
            名稱 說明
            0x0001 F_RELFLG 無重定位信息標(biāo)記。這個標(biāo)記指出COFF文件中沒有重定位信息。通常在目標(biāo)文件中這個標(biāo)記們?yōu)?,在可執(zhí)行文件中為1。
            0x0002 F_EXEC 可執(zhí)行標(biāo)記。這個標(biāo)記指出 COFF 文件中所有符號已經(jīng)解析, COFF 文件應(yīng)該被認(rèn)為是可執(zhí)行文件。
            0x0004 F_LNNO 文件中所有行號已經(jīng)被去掉。
            0x0008 F_LSYMS 文件中的符號信息已經(jīng)被去掉。
            0x0100 F_AR32WR 些標(biāo)記指出文件是 32 位的 Little-Endian COFF 文件。
                注:Little-Endian,記不得它的中文名稱了。它是指數(shù)據(jù)的排列方式。比如:十六進(jìn)制的0x1234以Little-Endian方式在內(nèi)存中的順序?yàn)?x34 0x12。與之相反的是Big-Endian,這種方式下,在內(nèi)存中的順序是0x12 0x34。
            這個表的內(nèi)容并不全面,但在目標(biāo)文件中,常用的也就只有這些。其它的標(biāo)記我將在以后介紹PE格式時(shí)給出。
            可選頭
                可選頭接在文件頭的后面,也就是從COFF文件的0x0014偏移處開始。長度可以為0。不同長度的可選頭,其結(jié)構(gòu)也不同。標(biāo)準(zhǔn)的可選頭長度為24或28字節(jié),通常是28啦。這里我就只介紹長度為28的可選頭。(因?yàn)檫@種頭的長度是自定義的,不同的人定義的結(jié)果就不一樣,我只能選一種最常用的頭來介紹,別的我也不知道)
            這種頭的結(jié)構(gòu)如下:
            typedef struct {
              unsigned short usMagic;  // 魔法數(shù)字
              unsigned short usVersion;  // 版本標(biāo)識
              unsigned long  ulTextSize;  // 正文(text)段大小
              unsigned long  ulInitDataSZ;  // 已初始化數(shù)據(jù)段大小
              unsigned long  ulUninitDataSZ;  // 未初始化數(shù)據(jù)段大小
              unsigned long  ulEntry;  // 入口點(diǎn)
              unsigned long  ulTextBase;  // 正文段基址
              unsigned long  ulDataBase;  // 數(shù)據(jù)段基址(在PE32中才有)
            } OPTHDR;
                第一個成員usMagic還是魔法數(shù)字,不過這回它的值應(yīng)該為0x010b或0x0107。當(dāng)值為0x010b時(shí),說明COFF文件是一個一般的可執(zhí)行文件;當(dāng)值為,0x0107時(shí),COFF則為一個ROM鏡像文件。
                usVersion是COFF文件的版本,ulTextSize是這個可執(zhí)行COFF的正文段長度,ulInitDataSZ和ulUninitDataSZ分別為已初始化數(shù)據(jù)段和未初始化數(shù)據(jù)段的長度。
                ulEntry是程序的入口點(diǎn),也就是COFF載入內(nèi)存時(shí)正文段的位置(EIP寄存器的值),當(dāng)COFF文件是一個動態(tài)庫時(shí),入口點(diǎn)也就是動態(tài)庫的入口函數(shù)。
                ulTextBase是正文段的基址。
                ulDataBase是數(shù)據(jù)段基址。
                其實(shí)在這些成員中,只要注意usMagic和ulEntry就可以了。

                段落頭
                段落頭緊跟在可選頭的后面(如果可選頭的長度為0,那么它就是緊跟在文件頭后)。它的長度為36個字節(jié),如下:
            typedef struct {
              char           cName[8];  // 段名
              unsigned long  ulVSize;  // 虛擬大小
              unsigned long  ulVAddr;  // 虛擬地址
              unsigned long  ulSize;  // 段長度
              unsigned long  ulSecOffset;  // 段數(shù)據(jù)偏移
              unsigned long  ulRelOffset;  // 段重定位表偏移
              unsigned long  ulLNOffset;  // 行號表偏移
              unsigned short ulNumRel;  // 重定位表長度
              unsigned short ulNumLN;  // 行號表長度
              unsigned long  ulFlags;  // 段標(biāo)識
            } SECHDR;
                這個頭可是個重要的頭頭,我們要用到的最終信息就由它來描述。一個COFF文件可以不要其它的節(jié),但文件頭和段落頭這兩節(jié)是必不可少的。
                cName用來保存段名,常用的段名有.text,.data,.comment,.bss等。.text段是正文段,通常也就是代碼段;.data是數(shù)據(jù)段,在這個數(shù)據(jù)段中所保存的數(shù)據(jù)是初始化過的數(shù)據(jù);.bss段也可以用來保存數(shù)據(jù),不過這里的數(shù)據(jù)是未初始化的,這個段也是一個空段;.comment段,看名字也知道,它是注釋段,用來保存一些編譯信息,算是對COFF文件的注釋。
                ulVSize是段數(shù)據(jù)載入內(nèi)存時(shí)的大小。只在可執(zhí)行文件中有效,在目標(biāo)文件中總為0。如果它的長度大于段的實(shí)際長度,則多的部分將用0來填充。
                ulVAddr是段數(shù)據(jù)載入或連接時(shí)的虛擬地址。對于可執(zhí)行文件來說,這個地址是相對于它的地址空間而言。當(dāng)可執(zhí)行文件被載入內(nèi)存時(shí),這個地址就是段中數(shù)據(jù)的第一個字節(jié)的位置。而對于目標(biāo)文件而言,這只是重定位時(shí),段數(shù)據(jù)當(dāng)前位置的一個偏移量。為了計(jì)算方便,便定位的計(jì)算簡化,它通常設(shè)為0。
                ulSize這才是段中數(shù)據(jù)的實(shí)際長度,也就是段數(shù)據(jù)的長度,在讀取段數(shù)據(jù)時(shí)就由它來確定要讀多少字節(jié)。
                ulSecOffset是段數(shù)據(jù)在COFF文件中的偏移量。
                ulRelOffset是該段的重定位信息的偏移量。它指向了重定位表的一個記錄。
                ulLNOffset是該段的行號表的偏移量。它指向的是行號表中的一個記錄。
                ulNumRel是重定位信息的記錄數(shù)。從ulRelOffset指向的記錄開始,到第ulNumRel個記錄為止,都是該段的重定位信息。
                ulNumLN和ulNumRel相似。不過它是行號信息的記錄數(shù)。
                ulFlags是該段的屬性標(biāo)識。其值如下表:
            名稱 說明
            0x0020 STYP_TEXT 正文段標(biāo)識,說明該段是代碼。
            0x0040 STYP_DATA 數(shù)據(jù)段標(biāo)識,有些標(biāo)識的段將用來保存已初始化數(shù)據(jù)。
            0x0080 STYP_BSS 有這個標(biāo)識段也是用來保存數(shù)據(jù),不過這里的數(shù)據(jù)是未初始化數(shù)據(jù)。
                注意,在BSS段中,ulVSize、ulVAddr、ulSize、ulSecOffset、ulRelOffset、ulLNOffset、ulNumRel、ulNumLN的值都為0。(上表只是部分值,其它值在PE格式中介紹,后同)

                段數(shù)據(jù)
                “人”如其名,這里是保存各個段的數(shù)據(jù)的位置。不同類型的段,數(shù)據(jù)的內(nèi)容、結(jié)構(gòu)也不盡相同。但在目標(biāo)文件中,這些數(shù)據(jù)都是原始數(shù)據(jù)(Raw Data)。不存在什么特別的格式。

                重定位表
                這個表所保存的是各個段的重定位信息。這是一張很大的表,因?yàn)樗卸蔚闹囟ㄎ恍畔⒍荚谶@個表里。各個段落頭記錄了自己的重定位信息的偏移和數(shù)量。要用到重定位信息時(shí)就到這個表里來讀。當(dāng)然,你也可以把整個重定位表看成多個重定位表,每個段落都有一個自己的重定位表。這個表只在目標(biāo)文件中有,可執(zhí)行文件中是不存在這個表的。
                既然有表,那么就會有記錄。重定位表中的每一條記錄就是一條重定位信息。這個記錄的結(jié)構(gòu)很簡單,如下:
            typedef struct {
              unsigned long  ulAddr;  // 定位偏移
              unsigned long  ulSymbol;  // 符號
              unsigned short usType;  // 定位類型
            } RELOC;
                有夠簡單吧,一共只三個成員!ulAddr是要定位的內(nèi)容在段內(nèi)偏移。比如:一個正文段,起始位置為0x010,ulAddr的值為0x05,那你的定位信息就要寫在0x15處。而且信息的長度要看你的代碼的類型,32位的代碼要寫4個字節(jié),16位的就只要字2個字節(jié)。
                ulSymbol是符號索引,它指向符號表中的一個記錄。注意,這里是索引,不是偏移!它只是符號表中的一個記錄的記錄號。這個成員指明了重定位信息所對映的符號。
            usType是重定位類型的標(biāo)識。32位代碼中,通常只用兩種定位方式。一是絕對定位,二是相對定位。其代碼如下:
            名稱 說明
            6 RELOC_ADDR32 32位絕對定位。
            20 RELOC_REL32 32位相對定位。
                對于不同的處理器,這些值也不盡相同。這里給出的是i386平臺上最常用的兩個種定位方式的標(biāo)識。
                其定位方式如下:
                絕對定位
                在絕對定位方式下,你要給出符號的絕對地址(注意,有時(shí)候這里可能不是地址,而是值,對于常量來說,你不用給出它的地值,只用給出它的值)。當(dāng)然,這個地址也不是現(xiàn)成的,你要用符號的相對地址+它所在段的相對地址來得到它的絕對地址。
                公式:符號絕對地址=段偏移+符號偏移
                這些偏移量你要分別從段落頭和符號表中得到。當(dāng)段落要重定位時(shí),當(dāng)然還要先重定位段落,才能定位其中的符號。
                相對定位
                相對定位要復(fù)雜一些。它所要的地址信息是相對于當(dāng)前位置的偏移,這個當(dāng)前位置就是ulAddr所指向的這個偏移的絕對地址后四個字節(jié)(32位代碼是四個字節(jié),16位是兩個字節(jié))的位置。也就是用定位偏移+當(dāng)前段偏移+機(jī)器字長÷8
                公式:當(dāng)前地址=定位偏移+當(dāng)前段偏移+機(jī)器字長÷8
                有了當(dāng)前地址,相對地址就好計(jì)算了。只要用符號的絕對地址減去當(dāng)前地址就可以了。
                公式:相對地址=符號絕對地址-當(dāng)前地址
                計(jì)算好了地址,把它寫到ulAddr所指向的位置,就一切OK!你已經(jīng)完成了重定位的工作了。

                行號表
                行號表在調(diào)試時(shí)很有用。它把可執(zhí)行的二進(jìn)制代碼與源代碼的行號之間建立了對映關(guān)系。這樣,當(dāng)程序執(zhí)行不正確時(shí)(其實(shí)正確的也可以J),我們就可以根據(jù)當(dāng)前執(zhí)行代碼的位置得知出錯源代碼的行號,再加以修改。如果沒有它的話,鬼才知道是哪一行出了毛病!
                它的格式也很簡單。只有兩個成員,如下:
            typedef struct {
                unsigned long ulAddrORSymbol;  // 代碼地址或符號索引
                unsigned short usLineNo;  // 行號
            } LINENO;
                讓我們先看第二個成員,usLineNo。這是一個從1開始計(jì)數(shù)的計(jì)數(shù)器,它代表源代碼的行號。第一個成員ulAddrORSymbol在行號大于0時(shí),代表源代碼的地址;而當(dāng)行號為0時(shí),它就成了行號所對映的符號在符號表中的索引。下面讓我們來看看符號表吧!

                符號表
                符號表是對象文件中用來保存符號信息的一張表,也是COFF文件中最為復(fù)雜的一張表。所有段落使用到的符號都在這個表里。它也是由很多條記錄組成,每條記錄都以如下結(jié)構(gòu)保存:
            typedef struct {
              union {
                char cName[8];            // 符號名稱
                struct {
                  unsigned long ulZero;   // 字符串表標(biāo)識
                  unsigned long ulOffset; // 字符串偏移
                } e;
              } e;
              unsigned long ulValue;     // 符號值
              short iSection;            // 符號所在段
              unsigned short usType;     // 符號類型
              unsigned char usClass;     // 符號存儲類型
              unsigned char usNumAux;    // 符號附加記錄數(shù)
            } SYMENT;
                cName符號名稱,和前面所有的名稱一樣,它也是8個字節(jié),但不同的是它在一個聯(lián)合體中。和它占相同的存儲空間的還有ulZero和ulOffset這兩個成員。如果符號的名稱只有8個字符,那很好,可以直接放到這個cName中;可是,如果名稱的長度大于8個字節(jié),這里就放不下了,只好放到字符串表中。這時(shí)候,ulZero的值就會為0,而在ulOffset中會給出我們所用的符號的名稱在字符串表中的偏移。
                一個符號有了名稱不夠,它還要有值!ulValue就是這個符號所代表的值。
                iSection成員指出了這個符號所在的段落。如果它的值為0,那么這個符號就是一個外部符號,要從其它的COFF文件中解析(連接多個目標(biāo)文件就是要解析這種符號)。當(dāng)它的值為-1時(shí),說明這個符號的值是一個常量,不是它在段落中的偏移。而當(dāng)它的值為-2時(shí),這個符號只是一個調(diào)試符號,只有在調(diào)試時(shí)才會用到它。當(dāng)它大于0時(shí),才是符號所在段的索引值。
                usType是符號的類型標(biāo)識。它用來說明這個符號的類型,是函數(shù)?整型?還是其它什么。這個標(biāo)識是兩個字節(jié)。
                低字節(jié)的低四位是基本標(biāo)識,它指出了符號的基本類型,如整型,字符,結(jié)構(gòu),聯(lián)合等。高四位指出了符號的高級類型,如指針(0001b),函數(shù)(0010b),數(shù)組(0011b),無類型(0000b)等。現(xiàn)在的編譯器,通常不使用基本類型,只使用高級類型。所以,符號的基本類型通常被設(shè)為0。
            高字節(jié)通常未用。
                usClass是符號的存儲類型標(biāo)識。它指明了符號的存儲方式。
                其值與意義見下表:
            名稱 說明
            NULL 0 無存儲類型。
            AUTOMATIC 1 自動類型。通常是在棧中分配的變量。
            EXTERNAL 2 外部符號。當(dāng)為外部符號時(shí),iSection的值應(yīng)該為0,如果不為0,則ulValue為符號在段中的偏移。
            STATIC 3 靜態(tài)類型。ulValue為符號在段中的偏移。如果偏移為0,那么這個符號代表段名。
            REGISTER 4 寄存器變量。
            MEMBER_OF_STRUCT 8 結(jié)構(gòu)成員。ulValue值為該符號在結(jié)構(gòu)中的順序。
            STRUCT_TAG 10 結(jié)構(gòu)標(biāo)識符。
            MEMBER_OF_UNION 11 聯(lián)合成員。ulValue值為該符號在聯(lián)合中的順序。
            UNION_TAG 12 聯(lián)合標(biāo)識符。
            TYPE_DEFINITION 13 類型定義。
            FUNCTION 101 函數(shù)名。
            FILE 102 文件名。
                最后一個成員usNumAux是附加記錄的數(shù)量。附加記錄是用來描述符號的一些附加信息,為了便于保存,這些附加記錄通常選擇成為一條符號信息記錄的整數(shù)倍(多數(shù)為1)。所以,如果這個成員的值為1,那么就表示在當(dāng)前符號信息記錄后附加了一條記錄,用來保存附加信息。
                附加信息的結(jié)構(gòu)是與符號的類型以及存儲類型相關(guān)的。不同的類型的符號,其附加信息(如果有的話)的結(jié)構(gòu)也不同。如果你不在意這些內(nèi)容,也可以把它們乎略。
                 當(dāng)段的類型為FILE時(shí),附加信息就是一個字符串,它是目標(biāo)文件對應(yīng)源文件的名稱。其它類型在介紹PE時(shí)再進(jìn)行詳細(xì)討論。

                字符串表
                不用多說,瞎子也能看出這個表是用來保存字符串的。它緊接在符號表后。至于為什么要保存字符串,前面已經(jīng)說過了。這里就不再多說了,只說說字符串的保存格式。
                 字符串表是所有節(jié)中最簡單一節(jié)。如下圖:0                             4                        
            字符串表長度 字符串1\0
            .... 字符串n\0

                字符串表的前四個字節(jié)是字符串表的長度,以字節(jié)為單位。其后就是以0結(jié)尾的字符串(C風(fēng)格字符串)。要注意的是,字符串表的長度不僅僅是字符串的長度(這個長度要包括每個字符串后的‘\0’)的總合,它還包括這個長度域的四個字節(jié)。符號表中ulOffset成員所指出的偏移就是從字符串表起始處的偏移。比如:指像每一個字符串的符號,ulOffset的值總為4。
                下面給出的代碼,是從字符串表中讀取字符串的典型C代碼。

            int iStrlen,iCur=4;                 // iStrLen是字符串表的長度,iCur是當(dāng)前字符串偏移
            char *str;                          // 字符串表
            read(fn, &iStrlen, 4);              // 得到字符串表長度
            str = (char *)malloc(iStrlen);      // 為字符串表分配空間
            while (iCur<iStrlen )               // 讀字符串表,直到全部讀入內(nèi)存
                iCur+=read(fn, str+iCur, iStrlen- iCur);
            iCur=4;                             // 把當(dāng)前字符串偏移指到每一個字符串
            while (iCur<iStrlen ) {             // 顯示每一個字符串
                printf("String offset 0x%04X : %s\n", iCur, str + iCur);
                iCur+=(strlen(str+iCur)+1);     // 計(jì)算偏移時(shí)不要忘了計(jì)算‘\0’字符所占的1個字節(jié)!
            }
            free(str);                          // 釋放字符串表空間     直到這里,整個COFF的結(jié)構(gòu)已經(jīng)全部介紹完了。很多了解PE格式的朋友一定會奇怪,好像少了很多內(nèi)容!?是的,標(biāo)準(zhǔn)的COFF文件只有這么多的東西。但MS為了和DOS的可執(zhí)行文件兼容,以及對可執(zhí)行文件功能的擴(kuò)展,在COFF格式中加了很多它自己的標(biāo)準(zhǔn)。讓我差點(diǎn)就認(rèn)不出COFF了。但了解了COFF文件以后,再來學(xué)習(xí)PE文件的格式,那就很簡單了。
                想了解PE文件的格式?網(wǎng)上有很多它的資料,我將在本文的基礎(chǔ)上再寫幾篇文章,分別介紹PE,OMF以及ELF的格式。
                現(xiàn)在大家可以自己動手,寫一個COFF文件解析器或是一個簡單的連接程序了!

            posted on 2008-03-24 10:17 葉子 閱讀(766) 評論(0)  編輯 收藏 引用 所屬分類: C\C++

            精品国产乱码久久久久久郑州公司| 麻豆精品久久精品色综合| 久久国产一片免费观看| 久久精品无码免费不卡| 色偷偷久久一区二区三区| 青青国产成人久久91网| 人妻无码αv中文字幕久久琪琪布| 久久青青草原精品国产| 日本精品一区二区久久久| 久久久久人妻精品一区二区三区| 97久久精品人人澡人人爽| 亚洲香蕉网久久综合影视 | 国产一级做a爰片久久毛片| 日韩亚洲欧美久久久www综合网 | segui久久国产精品| 欧美亚洲国产精品久久久久| 97久久天天综合色天天综合色hd| 亚洲美日韩Av中文字幕无码久久久妻妇 | 久久亚洲精精品中文字幕| 精品久久久久久久久久中文字幕 | 国内精品久久久久久99| 午夜精品久久久久9999高清| 国产精品久久自在自线观看| 久久久久人妻一区二区三区 | 久久亚洲国产精品五月天婷| 国产精品久久久久无码av| 色综合久久久久综合体桃花网| 久久精品人妻一区二区三区| 色综合久久综精品| 久久777国产线看观看精品| 无码伊人66久久大杳蕉网站谷歌| 伊人色综合久久天天网| 亚洲&#228;v永久无码精品天堂久久 | 精品国产一区二区三区久久蜜臀| 欧美伊香蕉久久综合类网站| 久久91综合国产91久久精品| 精品久久久久久久| 久久国产V一级毛多内射| 久久男人AV资源网站| 久久久久久毛片免费看| 久久天天躁狠狠躁夜夜av浪潮|