編譯器編譯過程探究

編譯器編譯過程探究

該度過 2019-05-07 11:15:49  246  收藏 1
展開
摘要: 完整的語言處理系統包括預處理器、編譯器、彙編器、連接-編輯器四個組成部分。一個典型的編譯過程爲:預處理器將源程序中的宏展開爲原始語句加入到源程序中,編譯器則產生彙編代碼,彙編代碼交由彙編器產生可重定位機器代碼,然後與一些庫程序連接在一起形成絕對機器代碼,即可在計算機上執行的代碼。本文以GCC爲工具,對簡單的C,C++程序進行編譯,觀察其各個部分的輸出內容,探究語言處理系統所做的完整工作。

關鍵字:預處理 編譯 彙編 鏈接 問題探究

1 引言

        一個 C 或者 C++ 語言程序在編譯成爲可執行目標程序的過程中需要經歷預處理、編譯、彙編、鏈接四個階段。如下圖所示:

源程序
目標彙編程序
可重定位機器代碼
絕對機器代碼
預處理器
編譯器
彙編器
連接器
可執行目標程序
本文將採用如下幾段 C 或 C++ 代碼,對編譯的過程及結果進行分析,探究語言系統所做的完整工作。

// test.cc
#include<iostream>
using namespace std;
int main(){
    int i,n,f;
    cin>>n;
    i=2;
    f=1;
    while(i<=n){
        f=f*i;
        i=i+1;
    }
    cout<<f<<endl;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//test2.c
#include <stdio.h>
#include "mymath.h"// 自定義頭文件
int main(){
    int a = 2;
    int b = 3;
    int sum = add(a, b); 
    printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
}
1
2
3
4
5
6
7
8
9
// mymath.h(儲存在文件夾 math 中)
#ifndef MYMATH_H
#define MYMATH_H
int add(int a, int b){return a+b;}
int sub(int a, int b){return a-b;}
#endif
1
2
3
4
5
6
2 預處理階段

        預處理器產生編譯器的輸入。通過預處理,可以將儲存在不同文件中的程序模塊集成爲一個完成的源程序,另外還可以將宏展開爲原始語句加入到頭文件中。其功能概括爲:宏處理、文件包含、語言擴充、'理性’預處理器。
在命令行中執行語句:
Gcc -E test.cc -o test.ii 和 Gcc -E -I./math test2.c -o test2.i
此處,-E 要求 Gcc 只進行預處理而不進行後面的三個階段,-I 指出頭文件所在的目錄, -o 指目標文件,.i 文件爲預處理後的 C 源程序。預處理後的代碼如下:

//test.ii  (由於原文件過長,此處截取了部分代碼)
# 1 "test.cc"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test.cc"
namespace std
{
  typedef unsigned int size_t;
  typedef int ptrdiff_t;


  typedef decltype(nullptr) nullptr_t;

}
namespace std
{
  inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
namespace __gnu_cxx
{
  inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
namespace std
{


extern "C" {

 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswalnum (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswalpha (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswascii (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswcntrl (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswctype (wint_t, wctype_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswdigit (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswgraph (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswlower (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswprint (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswpunct (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswspace (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswupper (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswxdigit (wint_t);

__attribute__((__deprecated__))

 __attribute__((__cdecl__)) __attribute__((__nothrow__)) int is_wctype (wint_t, wctype_t);


__attribute__((__cdecl__)) __attribute__((__nothrow__)) int iswblank (wint_t);

 __attribute__((__cdecl__)) __attribute__((__nothrow__)) wint_t towlower (wint_t);
 __attribute__((__cdecl__)) __attribute__((__nothrow__)) wint_t towupper (wint_t);
 
 ...
 
 # 2 "test.cc"
using namespace std;
int main(){
 int i,n,f;
 cin>>n;
 i=2;
 f=1;
 while(i<=n){
  f=f*i;
  i=i+1;
 }
 cout<<f<<endl;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//test2.i (由於原文件過長,此處截取了部分代碼)
# 1 "test4.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "test4.c"
typedef struct _iobuf
{
  char *_ptr;
  int _cnt;
  char *_base;
  int _flag;
  int _file;
  int _charbuf;
  int _bufsiz;
  char *_tmpfname;
} FILE;

...

# 2 "test4.c" 2
# 1 "./math/mymath.h" 1

# 4 "./math/mymath.h"
int add(int a, int b){return a+b;}
int sub(int a, int b){return a-b;}
# 3 "test4.c" 2
int main(){
    int a = 2;
    int b = 3;
    int sum = add(a, b);
    printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
可以看出頭文件及宏定義的代碼已經加入到源程序中,所以 .i 文件的體積遠大於原文件的體積。

3 編譯階段

        編譯器是分階段執行的,如圖爲編譯器的一個典型的階段劃分:

源程序
詞法分析器
語法分析器
語義分析器
中間代碼生成器
代碼優化器
代碼生成器
目標程序
首先是對代碼進行語法檢查,此處運行命令行代碼 gcc -I./math -fsyntax-only test4.c,其中 test4.c 是 test2.c 中 add(a,b) 後去掉分號的文件。 命令行運行後給出如下信息:

test4.c: In function 'main':
test4.c:7:5: error: expected ',' or ';' before 'printf'
     printf("a=%d, b=%d, a+b=%d\n", a, b, sum);
     ^~~~~~
1
2
3
4
說明出現了語法錯誤,重新加上 ’ ; ',正常運行。

        另外,在編譯階段還可以對代碼進行優化,此處依次運行命令行代碼 :gcc -o test2.c,gcc -O3 test2.c,gcc -os test2.c. 其中,-o爲默認執行,不進行任何優化;-O3 爲優化等次3,-os 爲優化代碼大小,實際相當於優化等次2.5。將生成.exe文件分別爲:a.exe、3.exe、s.exe。不過由於windows下沒有直接顯示進程運行時間的命令,通過查閱資料,寫出如下的批處理,可以輸出運行的時間,其代碼如下:

//time.bat
@echo off
set /a StartMS=%time:~3,1%*60000 + %time:~4,1%*6000 + %time:~6,1%*1000 + %time:~7,1%*100 + %time:~9,1%*10 + %time:~10,1%
%1 %2 %3 %4 %5 %6
set /a EndMS =%time:~3,1%*60000 + %time:~4,1%*6000 + %time:~6,1%*1000 + %time:~7,1%*100 + %time:~9,1%*10 + %time:~10,1%
set /a realtime = %EndMS%-%StartMS%
echo %realtime%ms
1
2
3
4
5
6
7
運行命令:.\time.bat D:\Gcc\test2\a、.\time.bat D:\Gcc\test2\3、.\time.bat D:\Gcc\test2\s即可查看對應的運行時間,運行結果如下:

PS D:\Gcc\test2> .\time.bat D:\Gcc\test2\a
a=2, b=3, a+b=5
6ms
PS D:\Gcc\test2> .\time.bat D:\Gcc\test2\3
a=2, b=3, a+b=5
4ms
PS D:\Gcc\test2> .\time.bat D:\Gcc\test2\s
a=2, b=3, a+b=5
3ms
1
2
3
4
5
6
7
8
9
可以看出,未經優化時,運行消耗的時間更多,-os執行效率最高。

編譯階段的最終結果是生成機器目標代碼文件,執行命令:Gcc -S test.cc -o test.S、Gcc -S test4.c -o test4.S,生成彙編代碼如下:

test.S的內容:

    #test.S
    .file    "test.cc"
    .section .rdata,"dr"
__ZStL19piecewise_construct:
    .space 1
.lcomm __ZStL8__ioinit,1,1
    .def    ___main;    .scl    2;    .type    32;    .endef
    .text
    .globl    _main
    .def    _main;    .scl    2;    .type    32;    .endef
_main:
LFB1445:
    .cfi_startproc
    leal    4(%esp), %ecx
    .cfi_def_cfa 1, 0
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    .cfi_escape 0x10,0x5,0x2,0x75,0
    movl    %esp, %ebp
    pushl    %ecx
    .cfi_escape 0xf,0x3,0x75,0x7c,0x6
    subl    $36, %esp
    call    ___main
    leal    -20(%ebp), %eax
    movl    %eax, (%esp)
    movl    $__ZSt3cin, %ecx
    call    __ZNSirsERi
    subl    $4, %esp
    movl    $2, -12(%ebp)
    movl    $1, -16(%ebp)
L3:
    movl    -20(%ebp), %eax
    cmpl    %eax, -12(%ebp)
    jg    L2
    movl    -16(%ebp), %eax
    imull    -12(%ebp), %eax
    movl    %eax, -16(%ebp)
    addl    $1, -12(%ebp)
    jmp    L3
L2:
    movl    -16(%ebp), %eax
    movl    %eax, (%esp)
    movl    $__ZSt4cout, %ecx
    call    __ZNSolsEi
    subl    $4, %esp
    movl    $__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, (%esp)
    movl    %eax, %ecx
    call    __ZNSolsEPFRSoS_E
    subl    $4, %esp
    movl    $0, %eax
    movl    -4(%ebp), %ecx
    .cfi_def_cfa 1, 0
    leave
    .cfi_restore 5
    leal    -4(%ecx), %esp
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE1445:
    .def    ___tcf_0;    .scl    3;    .type    32;    .endef
___tcf_0:
LFB1875:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $8, %esp
    movl    $__ZStL8__ioinit, %ecx
    call    __ZNSt8ios_base4InitD1Ev
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE1875:
    .def    __Z41__static_initialization_and_destruction_0ii;    .scl    3;    .type    32;    .endef
__Z41__static_initialization_and_destruction_0ii:
LFB1874:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $24, %esp
    cmpl    $1, 8(%ebp)
    jne    L8
    cmpl    $65535, 12(%ebp)
    jne    L8
    movl    $__ZStL8__ioinit, %ecx
    call    __ZNSt8ios_base4InitC1Ev
    movl    $___tcf_0, (%esp)
    call    _atexit
L8:
    nop
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE1874:
    .def    __GLOBAL__sub_I_main;    .scl    3;    .type    32;    .endef
__GLOBAL__sub_I_main:
LFB1876:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $24, %esp
    movl    $65535, 4(%esp)
    movl    $1, (%esp)
    call    __Z41__static_initialization_and_destruction_0ii
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE1876:
    .section    .ctors,"w"
    .align 4
    .long    __GLOBAL__sub_I_main
    .ident    "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
    .def    __ZNSirsERi;    .scl    2;    .type    32;    .endef
    .def    __ZNSolsEi;    .scl    2;    .type    32;    .endef
    .def    __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_;    .scl    2;    .type    32;    .endef
    .def    __ZNSolsEPFRSoS_E;    .scl    2;    .type    32;    .endef
    .def    __ZNSt8ios_base4InitD1Ev;    .scl    2;    .type    32;    .endef
    .def    __ZNSt8ios_base4InitC1Ev;    .scl    2;    .type    32;    .endef
    .def    _atexit;    .scl    2;    .type    32;    .endef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
以下爲test4.S的內容:

    //test4.S
    .file    "test4.c"
    .text
    .globl    _add
    .def    _add;    .scl    2;    .type    32;    .endef
_add:
LFB10:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    8(%ebp), %edx
    movl    12(%ebp), %eax
    addl    %edx, %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE10:
    .globl    _sub
    .def    _sub;    .scl    2;    .type    32;    .endef
_sub:
LFB11:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    movl    8(%ebp), %eax
    subl    12(%ebp), %eax
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE11:
    .def    ___main;    .scl    2;    .type    32;    .endef
    .section .rdata,"dr"
LC0:
    .ascii "a=%d, b=%d, a+b=%d\12\0"
    .text
    .globl    _main
    .def    _main;    .scl    2;    .type    32;    .endef
_main:
LFB12:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    call    ___main
    movl    $2, 28(%esp)
    movl    $3, 24(%esp)
    movl    24(%esp), %eax
    movl    %eax, 4(%esp)
    movl    28(%esp), %eax
    movl    %eax, (%esp)
    call    _add
    movl    %eax, 20(%esp)
    movl    20(%esp), %eax
    movl    %eax, 12(%esp)
    movl    24(%esp), %eax
    movl    %eax, 8(%esp)
    movl    28(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE12:
    .ident    "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
    .def    _printf;    .scl    2;    .type    32;    .endef

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
編譯器將高級語言源程序轉換爲彙編語言程序,體現在文件上爲將.i文件轉換爲.S文件。

4 彙編階段

        通過編譯器產生的彙編代碼需要交由彙編器進行進一步的處理,生成可重定位的機器代碼,體現在文件上爲將.S文件轉換爲.o文件。此時生成的.o文件爲二進制文件,文本編輯器將無法打開。爲查看生成文件的內容,此處採用GUN的objdump進行反彙編。具體過程爲:

Gcc test.S -o test.o //執行完彙編階段即停止
objdump -d test.o //對文件 test.o 進行反彙編
1
2
執行結果如下:

//反彙編後的代碼:

test.o:     file format pe-i386

Disassembly of section .text:

00000000 <_main>:
   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 f0                and    $0xfffffff0,%esp
   7:   ff 71 fc                pushl  -0x4(%ecx)
   a:   55                      push   %ebp
   b:   89 e5                   mov    %esp,%ebp
   d:   51                      push   %ecx
   e:   83 ec 24                sub    $0x24,%esp
  11:   e8 00 00 00 00          call   16 <_main+0x16>
  16:   8d 45 ec                lea    -0x14(%ebp),%eax
  19:   89 04 24                mov    %eax,(%esp)
  1c:   b9 00 00 00 00          mov    $0x0,%ecx
  21:   e8 00 00 00 00          call   26 <_main+0x26>
  26:   83 ec 04                sub    $0x4,%esp
  29:   c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%ebp)
  30:   c7 45 f0 01 00 00 00    movl   $0x1,-0x10(%ebp)
  37:   8b 45 ec                mov    -0x14(%ebp),%eax
  3a:   39 45 f4                cmp    %eax,-0xc(%ebp)
  3d:   7f 10                   jg     4f <_main+0x4f>
  3f:   8b 45 f0                mov    -0x10(%ebp),%eax
  42:   0f af 45 f4             imul   -0xc(%ebp),%eax
  46:   89 45 f0                mov    %eax,-0x10(%ebp)
  49:   83 45 f4 01             addl   $0x1,-0xc(%ebp)
  4d:   eb e8                   jmp    37 <_main+0x37>
  4f:   8b 45 f0                mov    -0x10(%ebp),%eax
  52:   89 04 24                mov    %eax,(%esp)
  55:   b9 00 00 00 00          mov    $0x0,%ecx
  5a:   e8 00 00 00 00          call   5f <_main+0x5f>
  5f:   83 ec 04                sub    $0x4,%esp
  62:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
  69:   89 c1                   mov    %eax,%ecx
  6b:   e8 00 00 00 00          call   70 <_main+0x70>
  70:   83 ec 04                sub    $0x4,%esp
  73:   b8 00 00 00 00          mov    $0x0,%eax
  78:   8b 4d fc                mov    -0x4(%ebp),%ecx
  7b:   c9                      leave
  7c:   8d 61 fc                lea    -0x4(%ecx),%esp
  7f:   c3                      ret

00000080 <___tcf_0>:
  80:   55                      push   %ebp
  81:   89 e5                   mov    %esp,%ebp
  83:   83 ec 08                sub    $0x8,%esp
  86:   b9 00 00 00 00          mov    $0x0,%ecx
  8b:   e8 00 00 00 00          call   90 <___tcf_0+0x10>
  90:   c9                      leave
  91:   c3                      ret

00000092 <__Z41__static_initialization_and_destruction_0ii>:
  92:   55                      push   %ebp
  93:   89 e5                   mov    %esp,%ebp
  95:   83 ec 18                sub    $0x18,%esp
  98:   83 7d 08 01             cmpl   $0x1,0x8(%ebp)
  9c:   75 1f                   jne    bd <__Z41__static_initialization_and_destruction_0ii+0x2b>
  9e:   81 7d 0c ff ff 00 00    cmpl   $0xffff,0xc(%ebp)
  a5:   75 16                   jne    bd <__Z41__static_initialization_and_destruction_0ii+0x2b>
  a7:   b9 00 00 00 00          mov    $0x0,%ecx
  ac:   e8 00 00 00 00          call   b1 <__Z41__static_initialization_and_destruction_0ii+0x1f>
  b1:   c7 04 24 80 00 00 00    movl   $0x80,(%esp)
  b8:   e8 00 00 00 00          call   bd <__Z41__static_initialization_and_destruction_0ii+0x2b>
  bd:   90                      nop
  be:   c9                      leave
  bf:   c3                      ret

000000c0 <__GLOBAL__sub_I_main>:
  c0:   55                      push   %ebp
  c1:   89 e5                   mov    %esp,%ebp
  c3:   83 ec 18                sub    $0x18,%esp
  c6:   c7 44 24 04 ff ff 00    movl   $0xffff,0x4(%esp)
  cd:   00
  ce:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)
  d5:   e8 b8 ff ff ff          call   92 <__Z41__static_initialization_and_destruction_0ii>
  da:   c9                      leave
  db:   c3                      ret
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
5 裝載-連接階段

        裝配器完成程序的裝入和連接編輯兩項功能。裝入過程包括讀入可重定位機器代碼,修改可重定位地址,並將修改後的指令和數據放到內存中的合適位置。連接編輯器將多個重定位機器代碼的文件組裝成爲一個程序。

        經過彙編之後的.o文件依然是不可執行的,只有經過連接階段,將程序所引用的外部文件關聯起來,生成.exe文件纔是可執行的程序。

        連接的方式有靜態鏈接與動態鏈接,動態鏈接的代碼是存放在動態鏈接庫或者某個共享對象的目標文件中,不會將庫的內容拷貝到可執行程序中,所以生成的程序的體積較小;而靜態鏈接庫則將需要的代碼從相應的靜態鏈接庫中拷貝到可執行程序中。此處採用了動態鏈接庫的方式。命令代碼爲:

gcc -fPIC -shared test.cc -o libtest.so  //鏈接庫libtest.so
gcc test.o -o test  //生成可執行程序test.exe
.\test  //執行test.exe  
1
2
3
運行結果如下:

D:\Gcc\test>.\test
5
120
1
2
3
libtest.so 反彙編後的代碼(由於文件過長截取部分內容,詳見附件):

D:\Gcc\test>objdump -d libtest.so

libtest.so:     file format pei-i386


Disassembly of section .text:

61d41000 <.text>:
61d41000:       53                      push   %ebx
61d41001:       83 ec 18                sub    $0x18,%esp
61d41004:       8b 15 04 50 d4 61       mov    0x61d45004,%edx
61d4100a:       85 d2                   test   %edx,%edx
61d4100c:       74 39                   je     61d41047 <.text+0x47>

        .......

61d41ba0 <__DTOR_LIST__>:
61d41ba0:       ff                      (bad)
61d41ba1:       ff                      (bad)
61d41ba2:       ff                      (bad)
61d41ba3:       ff 00                   incl   (%eax)
61d41ba5:       00 00                   add    %al,(%eax)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        

參考

肖文鵬. Linux彙編語言開發指南(EB/OL). http://www.ibm.com/developerworks/cn/linux/l-assembly/index.html, 2003-07-03
作者不詳. GCC優化選項的各種含義以及潛藏風險(EB/OL). http://www.360doc.com/content/16/0802/17/478627_580294703.shtml, 2016-08-02
作者不詳. bat時間的運算與提取(EB/OL). https://www.cnblogs.com/--3q/p/5723277.html, 2016-07-31
gcc manual(EB/OL). http://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/
gcc中文文檔
————————————————
版權聲明:本文爲CSDN博主「該度過」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_39999637/article/details/82857251

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章