aytony

求古寻论,散虑逍遥。

0%

C++可执行文件的生成

头文件、源文件和库

一般惯例

  • 头文件:包括函数、结构体、类、变量等的声明,一般不包含核心变量及函数的定义与实例。
  • 源文件:包括函数的定义、变量的定义、类的定义等成分。
  • 库文件:包括函数的定义、变量的定义、类的定义等成分,由源文件生成。

举例:cstdio

头文件:cstdio

1
2
3
...
int __cdecl printf(const char * __restrict__ _Format,...);
...

源文件:main.cpp

1
2
3
4
5
6
7
#include <cstdio>
#include <cstdlib>
int main()
{
printf("hello, world!\n");
return EXIT_SUCCESS;
}

库文件:libstdc++.a

可执行程序的生成流程

编译器及版本

1
2
3
4
g++.exe (x86_64-win32-seh-rev3, Built by MinGW-W64 project) 12.1.0
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

预处理

对源文件所有预处理代码进行转义等操作。

1
g++ -E main.cpp -o main.cxx 

文件:main.cxx

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
# 0 ".\\main.cpp"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 ".\\main.cpp"
# 1 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/cstdio" 1 3
# 39 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/cstdio" 3

# 40 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/cstdio" 3

# 1 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 1 3
# 296 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3

# 296 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3
namespace std
{
typedef long long unsigned int size_t;
typedef long long int ptrdiff_t;


typedef decltype(nullptr) nullptr_t;


#pragma GCC visibility push(default)


extern "C++" __attribute__ ((__noreturn__, __always_inline__))
inline void __terminate() noexcept
{
void terminate() noexcept __attribute__ ((__noreturn__));
terminate();
}
#pragma GCC visibility pop
}
# 329 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3
namespace std
{
inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
namespace __gnu_cxx
{
inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
}
# 508 "C:/Users/shuij/Documents/portables/mingw64/lib/gcc/x86_64-w64-mingw32/12.1.0/include/c++/x86_64-w64-mingw32/bits/c++config.h" 3

...
// 省略2100行
...

namespace std
{

using ::__gnu_cxx::lldiv_t;

using ::__gnu_cxx::_Exit;

using ::__gnu_cxx::llabs;
using ::__gnu_cxx::div;
using ::__gnu_cxx::lldiv;

using ::__gnu_cxx::atoll;
using ::__gnu_cxx::strtof;
using ::__gnu_cxx::strtoll;
using ::__gnu_cxx::strtoull;
using ::__gnu_cxx::strtold;
}



}
# 3 ".\\main.cpp" 2


# 4 ".\\main.cpp"
using namespace std;

int main()
{
printf("hello, world!\n");
return
# 9 ".\\main.cpp" 3
0
# 9 ".\\main.cpp"
;
}

编译

将转义完成的C++文件转化为汇编代码

1
g++ -S main.cxx -o main.s 

文件:main.s

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
	.file	"main.cxx"
.text
.section .text$_Z6printfPKcz,"x"
.linkonce discard
.globl _Z6printfPKcz
.def _Z6printfPKcz; .scl 2; .type 32; .endef
.seh_proc _Z6printfPKcz
_Z6printfPKcz:
.LFB10:
pushq %rbp
.seh_pushreg %rbp
pushq %rbx
.seh_pushreg %rbx
subq $56, %rsp
.seh_stackalloc 56
leaq 48(%rsp), %rbp
.seh_setframe %rbp, 48
.seh_endprologue
movq %rcx, 32(%rbp)
movq %rdx, 40(%rbp)
movq %r8, 48(%rbp)
movq %r9, 56(%rbp)
leaq 40(%rbp), %rax
movq %rax, -16(%rbp)
movq -16(%rbp), %rbx
movl $1, %ecx
movq __imp___acrt_iob_func(%rip), %rax
call *%rax
movq %rax, %rcx
movq 32(%rbp), %rax
movq %rbx, %r8
movq %rax, %rdx
call __mingw_vfprintf
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $56, %rsp
popq %rbx
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "hello, world!\12\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
.LFB80:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
call __main
leaq .LC0(%rip), %rax
movq %rax, %rcx
call _Z6printfPKcz
movl $0, %eax
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-win32-seh-rev3, Built by MinGW-W64 project) 12.1.0"
.def __mingw_vfprintf; .scl 2; .type 32; .endef

汇编

将汇编代码转化为二进制机器码

1
g++ -c main.s -o main.o 

链接

将所有二进制机器码进行统一,生成可执行文件

1
g++ main.o -o main.exe 

一步生成

1
g++ main.cpp -o main.exe

总览