使用-O3
编译此代码:
#include <iostream>
int main(){std::cout<<"Hello World"<<std::endl;}
会生成长度为25,890
个字节的文件。 (用GCC 4.8.1编制)
编译器是否只能存储两个对write(STDOUT_FILENO, ???, strlen(???));
的调用,存储write
的内容,存储字符串,然后将它写入磁盘?它应该导致EXE的长度低于我估计的1,024
字节。
在17
字节文件中编译汇编结果中的hello world程序:https://stackoverflow.com/questions/284797/hello-world-in-less-than-17-bytes,表示实际代码长度为5个字节。 (字符串为Hello World\0
)
除了实际的main
及其调用的函数外,EXE还存储了什么?
注意:此问题也适用于MSVC。
编辑:
很多用户指出iostream
是罪魁祸首,所以我测试了这个假设并用相同的参数编译了这个程序:
int main( ) {
}
得到23,815
个字节,这个假设被否定了。
答案 0 :(得分:15)
编译器默认生成完整的符合PE的可执行文件。假设发布版本,您发布的简单代码可能包括:
如果编译器是MSVC,则会有其他内容:
您发布的链接确实包含一个非常小的组件&#34; hello world&#34;程序,但为了在Windows环境中正常运行,至少需要为加载程序提供完整有效的PE结构(将所有可能导致该代码无法运行的低级问题放在一边)。
假设装载程序已经正确地设置了&#39;将代码运行到的过程,只有在那时你可以将它映射到PE部分并执行
jmp small_hello_world_entry_point
实际执行代码。
参考文献:PE format
最后一个通知:UPX和类似的压缩工具也用于减少可执行文件的文件大小。
答案 1 :(得分:8)
C ++不是汇编,就像C一样,它带有很多基础设施。除了C的开销 - 需要与C abi兼容 - C ++也有许多东西的变种,并且它还必须具有提供许多保证所需的所有撕裂和缩减代码。语言。
其中大部分是由库提供的,但其中一些必须在可执行文件中,以便可以处理加载共享库的失败。
在Linux / BSD下,我们可以使用objdump -dsl
对可执行文件进行反向工程。我采用了以下代码:
int main() {}
并用以下内容编译:
g++ -Wall -O3 -g0 test.cpp -o test.exe
生成的可执行文件?
6922 bytes
然后我编写了较少的文章:
g++ -Wall -O3 -g0 test.cpp -o test.exe -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400150
基本上:main是我们的 C ++代码的门面入口点,程序真正从_start开始。
可执行文件大小?
1454 bytes
以下是objdump对两者的描述:
g++ -Wall -O3 -g0 test.cpp -o test.exe
objdump -test.exe
test.exe: file format elf64-x86-64
Contents of section .interp:
400200 2f6c6962 36342f6c 642d6c69 6e75782d /lib64/ld-linux-
400210 7838362d 36342e73 6f2e3200 x86-64.so.2.
Contents of section .note.ABI-tag:
40021c 04000000 10000000 01000000 474e5500 ............GNU.
40022c 00000000 02000000 06000000 12000000 ................
Contents of section .note.gnu.build-id:
40023c 04000000 14000000 03000000 474e5500 ............GNU.
40024c a0f55c7d 671f9eb2 93078fd3 0f52581a ..\}g........RX.
40025c 544829b2 TH).
Contents of section .hash:
400260 03000000 06000000 02000000 05000000 ................
400270 00000000 00000000 00000000 01000000 ................
400280 00000000 03000000 04000000 ............
Contents of section .dynsym:
400290 00000000 00000000 00000000 00000000 ................
4002a0 00000000 00000000 10000000 20000000 ............ ...
4002b0 00000000 00000000 00000000 00000000 ................
4002c0 1f000000 20000000 00000000 00000000 .... ...........
4002d0 00000000 00000000 8b000000 12000000 ................
4002e0 00000000 00000000 00000000 00000000 ................
4002f0 33000000 20000000 00000000 00000000 3... ...........
400300 00000000 00000000 4f000000 20000000 ........O... ...
400310 00000000 00000000 00000000 00000000 ................
Contents of section .dynstr:
400320 006c6962 73746463 2b2b2e73 6f2e3600 .libstdc++.so.6.
400330 5f5f676d 6f6e5f73 74617274 5f5f005f __gmon_start__._
400340 4a765f52 65676973 74657243 6c617373 Jv_RegisterClass
400350 6573005f 49544d5f 64657265 67697374 es._ITM_deregist
400360 6572544d 436c6f6e 65546162 6c65005f erTMCloneTable._
400370 49544d5f 72656769 73746572 544d436c ITM_registerTMCl
400380 6f6e6554 61626c65 006c6962 6d2e736f oneTable.libm.so
400390 2e36006c 69626763 635f732e 736f2e31 .6.libgcc_s.so.1
4003a0 006c6962 632e736f 2e36005f 5f6c6962 .libc.so.6.__lib
4003b0 635f7374 6172745f 6d61696e 00474c49 c_start_main.GLI
4003c0 42435f32 2e322e35 00 BC_2.2.5.
Contents of section .gnu.version:
4003ca 00000000 00000200 00000000 ............
Contents of section .gnu.version_r:
4003d8 01000100 81000000 10000000 00000000 ................
4003e8 751a6909 00000200 9d000000 00000000 u.i.............
Contents of section .rela.dyn:
4003f8 50096000 00000000 06000000 01000000 P.`.............
400408 00000000 00000000 ........
Contents of section .rela.plt:
400410 70096000 00000000 07000000 03000000 p.`.............
400420 00000000 00000000 ........
Contents of section .init:
400428 4883ec08 e85b0000 00e86a01 0000e845 H....[....j....E
400438 02000048 83c408c3 ...H....
Contents of section .plt:
400440 ff351a05 2000ff25 1c052000 0f1f4000 .5.. ..%.. ...@.
400450 ff251a05 20006800 000000e9 e0ffffff .%.. .h.........
Contents of section .text:
400460 31ed4989 d15e4889 e24883e4 f0505449 1.I..^H..H...PTI
400470 c7c0e005 400048c7 c1f00540 0048c7c7 ....@.H....@.H..
400480 d0054000 e8c7ffff fff49090 4883ec08 ..@.........H...
400490 488b05b9 04200048 85c07402 ffd04883 H.... .H..t...H.
4004a0 c408c390 90909090 90909090 90909090 ................
4004b0 90909090 90909090 90909090 90909090 ................
4004c0 b88f0960 00482d88 09600048 83f80e76 ...`.H-..`.H...v
4004d0 17b80000 00004885 c0740dbf 88096000 ......H..t....`.
4004e0 ffe0660f 1f440000 f3c3660f 1f440000 ..f..D....f..D..
4004f0 be880960 004881ee 88096000 48c1fe03 ...`.H....`.H...
400500 4889f048 c1e83f48 01c648d1 fe7411b8 H..H..?H..H..t..
400510 00000000 4885c074 07bf8809 6000ffe0 ....H..t....`...
400520 f3c36666 6666662e 0f1f8400 00000000 ..fffff.........
400530 803d5104 20000075 5f5553bb 80076000 .=Q. ..u_US...`.
400540 4881eb78 07600048 83ec0848 8b053e04 H..x.`.H...H..>.
400550 200048c1 fb034883 eb01488d 6c241048 .H...H...H.l$.H
400560 39d87322 0f1f4000 4883c001 4889051d 9.s"..@.H...H...
400570 042000ff 14c57807 6000488b 050f0420 . ....x.`.H....
400580 004839d8 72e2e835 ffffffc6 05f60320 .H9.r..5.......
400590 00014883 c4085b5d f3c3660f 1f440000 ..H...[]..f..D..
4005a0 bf880760 0048833f 007505e9 40ffffff ...`.H.?.u..@...
4005b0 b8000000 004885c0 74f15548 89e5ffd0 .....H..t.UH....
4005c0 5de92aff ffff9090 90909090 90909090 ].*.............
4005d0 31c0c390 90909090 90909090 90909090 1...............
4005e0 f3c36666 6666662e 0f1f8400 00000000 ..fffff.........
4005f0 48896c24 d84c8964 24e0488d 2d630120 H.l$.L.d$.H.-c.
400600 004c8d25 5c012000 4c896c24 e84c8974 .L.%\. .L.l$.L.t
400610 24f04c89 7c24f848 895c24d0 4883ec38 $.L.|$.H.\$.H..8
400620 4c29e541 89fd4989 f648c1fd 034989d7 L).A..I..H...I..
400630 e8f3fdff ff4885ed 741c31db 0f1f4000 .....H..t.1...@.
400640 4c89fa4c 89f64489 ef41ff14 dc4883c3 L..L..D..A...H..
400650 014839eb 72ea488b 5c240848 8b6c2410 .H9.r.H.\$.H.l$.
400660 4c8b6424 184c8b6c 24204c8b 7424284c L.d$.L.l$ L.t$(L
400670 8b7c2430 4883c438 c3909090 90909090 .|$0H..8........
400680 554889e5 53bb6807 60004883 ec08488b UH..S.h.`.H...H.
400690 05d30020 004883f8 ff74140f 1f440000 ... .H...t...D..
4006a0 4883eb08 ffd0488b 034883f8 ff75f148 H.....H..H...u.H
4006b0 83c4085b 5dc39090 ...[]...
Contents of section .fini:
4006b8 4883ec08 e86ffeff ff4883c4 08c3 H....o...H....
Contents of section .rodata:
4006c8 01000200 ....
Contents of section .eh_frame_hdr:
4006cc 011b033b 20000000 03000000 04ffffff ...; ...........
4006dc 3c000000 14ffffff 54000000 24ffffff <.......T...$...
4006ec 6c000000 l...
Contents of section .eh_frame:
4006f0 14000000 00000000 017a5200 01781001 .........zR..x..
400700 1b0c0708 90010000 14000000 1c000000 ................
400710 c0feffff 03000000 00000000 00000000 ................
400720 14000000 34000000 b8feffff 02000000 ....4...........
400730 00000000 00000000 24000000 4c000000 ........$...L...
400740 b0feffff 89000000 00518c05 86065f0e .........Q...._.
400750 4083078f 028e038d 0402580e 08000000 @.........X.....
400760 00000000 ....
Contents of section .ctors:
600768 ffffffff ffffffff 00000000 00000000 ................
Contents of section .dtors:
600778 ffffffff ffffffff 00000000 00000000 ................
Contents of section .jcr:
600788 00000000 00000000 ........
Contents of section .dynamic:
600790 01000000 00000000 01000000 00000000 ................
6007a0 01000000 00000000 69000000 00000000 ........i.......
6007b0 01000000 00000000 73000000 00000000 ........s.......
6007c0 01000000 00000000 81000000 00000000 ................
6007d0 0c000000 00000000 28044000 00000000 ........(.@.....
6007e0 0d000000 00000000 b8064000 00000000 ..........@.....
6007f0 04000000 00000000 60024000 00000000 ........`.@.....
600800 05000000 00000000 20034000 00000000 ........ .@.....
600810 06000000 00000000 90024000 00000000 ..........@.....
600820 0a000000 00000000 a9000000 00000000 ................
600830 0b000000 00000000 18000000 00000000 ................
600840 15000000 00000000 00000000 00000000 ................
600850 03000000 00000000 58096000 00000000 ........X.`.....
600860 02000000 00000000 18000000 00000000 ................
600870 14000000 00000000 07000000 00000000 ................
600880 17000000 00000000 10044000 00000000 ..........@.....
600890 07000000 00000000 f8034000 00000000 ..........@.....
6008a0 08000000 00000000 18000000 00000000 ................
6008b0 09000000 00000000 18000000 00000000 ................
6008c0 feffff6f 00000000 d8034000 00000000 ...o......@.....
6008d0 ffffff6f 00000000 01000000 00000000 ...o............
6008e0 f0ffff6f 00000000 ca034000 00000000 ...o......@.....
6008f0 00000000 00000000 00000000 00000000 ................
600900 00000000 00000000 00000000 00000000 ................
600910 00000000 00000000 00000000 00000000 ................
600920 00000000 00000000 00000000 00000000 ................
600930 00000000 00000000 00000000 00000000 ................
600940 00000000 00000000 00000000 00000000 ................
Contents of section .got:
600950 00000000 00000000 ........
Contents of section .got.plt:
600958 90076000 00000000 00000000 00000000 ..`.............
600968 00000000 00000000 56044000 00000000 ........V.@.....
Contents of section .data:
600978 00000000 00000000 00000000 00000000 ................
Contents of section .comment:
0000 4743433a 2028474e 55292034 2e342e37 GCC: (GNU) 4.4.7
0010 20323031 32303331 33202852 65642048 20120313 (Red H
0020 61742034 2e342e37 2d313129 00474343 at 4.4.7-11).GCC
0030 3a202847 4e552920 342e392e 782d676f : (GNU) 4.9.x-go
0040 6f676c65 20323031 35303132 33202870 ogle 20150123 (p
0050 72657265 6c656173 652900 rerelease).
Disassembly of section .init:
0000000000400428 <_init>:
_init():
400428: 48 83 ec 08 sub $0x8,%rsp
40042c: e8 5b 00 00 00 callq 40048c <call_gmon_start>
400431: e8 6a 01 00 00 callq 4005a0 <frame_dummy>
400436: e8 45 02 00 00 callq 400680 <__do_global_ctors_aux>
40043b: 48 83 c4 08 add $0x8,%rsp
40043f: c3 retq
Disassembly of section .plt:
0000000000400440 <__libc_start_main@plt-0x10>:
400440: ff 35 1a 05 20 00 pushq 0x20051a(%rip) # 600960 <_GLOBAL_OFFSET_TABLE_+0x8>
400446: ff 25 1c 05 20 00 jmpq *0x20051c(%rip) # 600968 <_GLOBAL_OFFSET_TABLE_+0x10>
40044c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400450 <__libc_start_main@plt>:
400450: ff 25 1a 05 20 00 jmpq *0x20051a(%rip) # 600970 <_GLOBAL_OFFSET_TABLE_+0x18>
400456: 68 00 00 00 00 pushq $0x0
40045b: e9 e0 ff ff ff jmpq 400440 <_init+0x18>
Disassembly of section .text:
0000000000400460 <_start>:
_start():
400460: 31 ed xor %ebp,%ebp
400462: 49 89 d1 mov %rdx,%r9
400465: 5e pop %rsi
400466: 48 89 e2 mov %rsp,%rdx
400469: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
40046d: 50 push %rax
40046e: 54 push %rsp
40046f: 49 c7 c0 e0 05 40 00 mov $0x4005e0,%r8
400476: 48 c7 c1 f0 05 40 00 mov $0x4005f0,%rcx
40047d: 48 c7 c7 d0 05 40 00 mov $0x4005d0,%rdi
400484: e8 c7 ff ff ff callq 400450 <__libc_start_main@plt>
400489: f4 hlt
40048a: 90 nop
40048b: 90 nop
000000000040048c <call_gmon_start>:
call_gmon_start():
40048c: 48 83 ec 08 sub $0x8,%rsp
400490: 48 8b 05 b9 04 20 00 mov 0x2004b9(%rip),%rax # 600950 <_DYNAMIC+0x1c0>
400497: 48 85 c0 test %rax,%rax
40049a: 74 02 je 40049e <call_gmon_start+0x12>
40049c: ff d0 callq *%rax
40049e: 48 83 c4 08 add $0x8,%rsp
4004a2: c3 retq
4004a3: 90 nop
4004a4: 90 nop
4004a5: 90 nop
4004a6: 90 nop
4004a7: 90 nop
4004a8: 90 nop
4004a9: 90 nop
4004aa: 90 nop
4004ab: 90 nop
4004ac: 90 nop
4004ad: 90 nop
4004ae: 90 nop
4004af: 90 nop
4004b0: 90 nop
4004b1: 90 nop
4004b2: 90 nop
4004b3: 90 nop
4004b4: 90 nop
4004b5: 90 nop
4004b6: 90 nop
4004b7: 90 nop
4004b8: 90 nop
4004b9: 90 nop
4004ba: 90 nop
4004bb: 90 nop
4004bc: 90 nop
4004bd: 90 nop
4004be: 90 nop
4004bf: 90 nop
00000000004004c0 <deregister_tm_clones>:
deregister_tm_clones():
4004c0: b8 8f 09 60 00 mov $0x60098f,%eax
4004c5: 48 2d 88 09 60 00 sub $0x600988,%rax
4004cb: 48 83 f8 0e cmp $0xe,%rax
4004cf: 76 17 jbe 4004e8 <deregister_tm_clones+0x28>
4004d1: b8 00 00 00 00 mov $0x0,%eax
4004d6: 48 85 c0 test %rax,%rax
4004d9: 74 0d je 4004e8 <deregister_tm_clones+0x28>
4004db: bf 88 09 60 00 mov $0x600988,%edi
4004e0: ff e0 jmpq *%rax
4004e2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
4004e8: f3 c3 repz retq
4004ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000004004f0 <register_tm_clones>:
register_tm_clones():
4004f0: be 88 09 60 00 mov $0x600988,%esi
4004f5: 48 81 ee 88 09 60 00 sub $0x600988,%rsi
4004fc: 48 c1 fe 03 sar $0x3,%rsi
400500: 48 89 f0 mov %rsi,%rax
400503: 48 c1 e8 3f shr $0x3f,%rax
400507: 48 01 c6 add %rax,%rsi
40050a: 48 d1 fe sar %rsi
40050d: 74 11 je 400520 <register_tm_clones+0x30>
40050f: b8 00 00 00 00 mov $0x0,%eax
400514: 48 85 c0 test %rax,%rax
400517: 74 07 je 400520 <register_tm_clones+0x30>
400519: bf 88 09 60 00 mov $0x600988,%edi
40051e: ff e0 jmpq *%rax
400520: f3 c3 repz retq
400522: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
400529: 1f 84 00 00 00 00 00
0000000000400530 <__do_global_dtors_aux>:
__do_global_dtors_aux():
400530: 80 3d 51 04 20 00 00 cmpb $0x0,0x200451(%rip) # 600988 <__bss_start>
400537: 75 5f jne 400598 <__do_global_dtors_aux+0x68>
400539: 55 push %rbp
40053a: 53 push %rbx
40053b: bb 80 07 60 00 mov $0x600780,%ebx
400540: 48 81 eb 78 07 60 00 sub $0x600778,%rbx
400547: 48 83 ec 08 sub $0x8,%rsp
40054b: 48 8b 05 3e 04 20 00 mov 0x20043e(%rip),%rax # 600990 <dtor_idx.6648>
400552: 48 c1 fb 03 sar $0x3,%rbx
400556: 48 83 eb 01 sub $0x1,%rbx
40055a: 48 8d 6c 24 10 lea 0x10(%rsp),%rbp
40055f: 48 39 d8 cmp %rbx,%rax
400562: 73 22 jae 400586 <__do_global_dtors_aux+0x56>
400564: 0f 1f 40 00 nopl 0x0(%rax)
400568: 48 83 c0 01 add $0x1,%rax
40056c: 48 89 05 1d 04 20 00 mov %rax,0x20041d(%rip) # 600990 <dtor_idx.6648>
400573: ff 14 c5 78 07 60 00 callq *0x600778(,%rax,8)
40057a: 48 8b 05 0f 04 20 00 mov 0x20040f(%rip),%rax # 600990 <dtor_idx.6648>
400581: 48 39 d8 cmp %rbx,%rax
400584: 72 e2 jb 400568 <__do_global_dtors_aux+0x38>
400586: e8 35 ff ff ff callq 4004c0 <deregister_tm_clones>
40058b: c6 05 f6 03 20 00 01 movb $0x1,0x2003f6(%rip) # 600988 <__bss_start>
400592: 48 83 c4 08 add $0x8,%rsp
400596: 5b pop %rbx
400597: 5d pop %rbp
400598: f3 c3 repz retq
40059a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
00000000004005a0 <frame_dummy>:
frame_dummy():
4005a0: bf 88 07 60 00 mov $0x600788,%edi
4005a5: 48 83 3f 00 cmpq $0x0,(%rdi)
4005a9: 75 05 jne 4005b0 <frame_dummy+0x10>
4005ab: e9 40 ff ff ff jmpq 4004f0 <register_tm_clones>
4005b0: b8 00 00 00 00 mov $0x0,%eax
4005b5: 48 85 c0 test %rax,%rax
4005b8: 74 f1 je 4005ab <frame_dummy+0xb>
4005ba: 55 push %rbp
4005bb: 48 89 e5 mov %rsp,%rbp
4005be: ff d0 callq *%rax
4005c0: 5d pop %rbp
4005c1: e9 2a ff ff ff jmpq 4004f0 <register_tm_clones>
4005c6: 90 nop
4005c7: 90 nop
4005c8: 90 nop
4005c9: 90 nop
4005ca: 90 nop
4005cb: 90 nop
4005cc: 90 nop
4005cd: 90 nop
4005ce: 90 nop
4005cf: 90 nop
00000000004005d0 <main>:
main():
4005d0: 31 c0 xor %eax,%eax
4005d2: c3 retq
4005d3: 90 nop
4005d4: 90 nop
4005d5: 90 nop
4005d6: 90 nop
4005d7: 90 nop
4005d8: 90 nop
4005d9: 90 nop
4005da: 90 nop
4005db: 90 nop
4005dc: 90 nop
4005dd: 90 nop
4005de: 90 nop
4005df: 90 nop
00000000004005e0 <__libc_csu_fini>:
__libc_csu_fini():
4005e0: f3 c3 repz retq
4005e2: 66 66 66 66 66 2e 0f data32 data32 data32 data32 nopw %cs:0x0(%rax,%rax,1)
4005e9: 1f 84 00 00 00 00 00
00000000004005f0 <__libc_csu_init>:
__libc_csu_init():
4005f0: 48 89 6c 24 d8 mov %rbp,-0x28(%rsp)
4005f5: 4c 89 64 24 e0 mov %r12,-0x20(%rsp)
4005fa: 48 8d 2d 63 01 20 00 lea 0x200163(%rip),%rbp # 600764 <__init_array_end>
400601: 4c 8d 25 5c 01 20 00 lea 0x20015c(%rip),%r12 # 600764 <__init_array_end>
400608: 4c 89 6c 24 e8 mov %r13,-0x18(%rsp)
40060d: 4c 89 74 24 f0 mov %r14,-0x10(%rsp)
400612: 4c 89 7c 24 f8 mov %r15,-0x8(%rsp)
400617: 48 89 5c 24 d0 mov %rbx,-0x30(%rsp)
40061c: 48 83 ec 38 sub $0x38,%rsp
400620: 4c 29 e5 sub %r12,%rbp
400623: 41 89 fd mov %edi,%r13d
400626: 49 89 f6 mov %rsi,%r14
400629: 48 c1 fd 03 sar $0x3,%rbp
40062d: 49 89 d7 mov %rdx,%r15
400630: e8 f3 fd ff ff callq 400428 <_init>
400635: 48 85 ed test %rbp,%rbp
400638: 74 1c je 400656 <__libc_csu_init+0x66>
40063a: 31 db xor %ebx,%ebx
40063c: 0f 1f 40 00 nopl 0x0(%rax)
400640: 4c 89 fa mov %r15,%rdx
400643: 4c 89 f6 mov %r14,%rsi
400646: 44 89 ef mov %r13d,%edi
400649: 41 ff 14 dc callq *(%r12,%rbx,8)
40064d: 48 83 c3 01 add $0x1,%rbx
400651: 48 39 eb cmp %rbp,%rbx
400654: 72 ea jb 400640 <__libc_csu_init+0x50>
400656: 48 8b 5c 24 08 mov 0x8(%rsp),%rbx
40065b: 48 8b 6c 24 10 mov 0x10(%rsp),%rbp
400660: 4c 8b 64 24 18 mov 0x18(%rsp),%r12
400665: 4c 8b 6c 24 20 mov 0x20(%rsp),%r13
40066a: 4c 8b 74 24 28 mov 0x28(%rsp),%r14
40066f: 4c 8b 7c 24 30 mov 0x30(%rsp),%r15
400674: 48 83 c4 38 add $0x38,%rsp
400678: c3 retq
400679: 90 nop
40067a: 90 nop
40067b: 90 nop
40067c: 90 nop
40067d: 90 nop
40067e: 90 nop
40067f: 90 nop
0000000000400680 <__do_global_ctors_aux>:
__do_global_ctors_aux():
400680: 55 push %rbp
400681: 48 89 e5 mov %rsp,%rbp
400684: 53 push %rbx
400685: bb 68 07 60 00 mov $0x600768,%ebx
40068a: 48 83 ec 08 sub $0x8,%rsp
40068e: 48 8b 05 d3 00 20 00 mov 0x2000d3(%rip),%rax # 600768 <__CTOR_LIST__>
400695: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
400699: 74 14 je 4006af <__do_global_ctors_aux+0x2f>
40069b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4006a0: 48 83 eb 08 sub $0x8,%rbx
4006a4: ff d0 callq *%rax
4006a6: 48 8b 03 mov (%rbx),%rax
4006a9: 48 83 f8 ff cmp $0xffffffffffffffff,%rax
4006ad: 75 f1 jne 4006a0 <__do_global_ctors_aux+0x20>
4006af: 48 83 c4 08 add $0x8,%rsp
4006b3: 5b pop %rbx
4006b4: 5d pop %rbp
4006b5: c3 retq
4006b6: 90 nop
4006b7: 90 nop
Disassembly of section .fini:
00000000004006b8 <_fini>:
_fini():
4006b8: 48 83 ec 08 sub $0x8,%rsp
4006bc: e8 6f fe ff ff callq 400530 <__do_global_dtors_aux>
4006c1: 48 83 c4 08 add $0x8,%rsp
4006c5: c3 retq
和较小的文件:
g++ -Wall -O3 -g0 test.cpp -o test.exe -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400150
test.exe: file format elf64-x86-64
Contents of section .note.gnu.build-id:
400120 04000000 14000000 03000000 474e5500 ............GNU.
400130 d4b1e35c 21d1f541 b81d3ac9 d62bac7a ...\!..A..:..+.z
400140 606b1ad4 `k..
Contents of section .text:
400150 31c0c3 1..
Contents of section .eh_frame_hdr:
400154 011b033b 10000000 01000000 fcffffff ...;............
400164 2c000000 ,...
Contents of section .eh_frame:
400168 14000000 00000000 017a5200 01781001 .........zR..x..
400178 1b0c0708 90010000 14000000 1c000000 ................
400188 c8ffffff 03000000 00000000 00000000 ................
Contents of section .comment:
0000 4743433a 2028474e 55292034 2e392e78 GCC: (GNU) 4.9.x
0010 2d676f6f 676c6520 32303135 30313233 -google 20150123
0020 20287072 6572656c 65617365 2900 (prerelease).
Disassembly of section .text:
0000000000400150 <main>:
main():
400150: 31 c0 xor %eax,%eax
400152: c3 retq
值得注意的是,这个可执行文件不起作用,它是段错误的:为了使其工作,我们实际上必须实现_start
而不是main
。
我们在这里可以看到,大部分较大的可执行文件是粘合代码,用于处理加载动态库和准备标准库所需的更广泛的环境。
---编辑---
即使我们较小的代码仍然必须包含异常处理,对全局变量的ctor / dtor支持等等。它可能会忽略这些事情,如果你深入挖掘,你可能会找到方法来消除它们,但总的来说你可能不需要,而且总是包括这样的基本支持可能比拥有大多数新的更容易程序员绊倒了“如何强制编译器发出基本语言支持”,而不是让一些新的嵌入式程序员问“如何防止编译器发出基本语言支持?”。
另请注意,编译器生成ELF格式二进制文件,这是一个很小的贡献(可能~60bytes),再加上它自己的身份添加了一些大小。但是较小的二进制文件的大部分是语言支持(EH和CTOR / DTOR)。
使用#include <iostream>
和-O3 -g0
进行编译会生成7625字节的二进制文件,如果我使用-O0 -g3
进行编译,则会生成64Kb二进制文件,其中大部分是描述STL符号的文本。
答案 2 :(得分:3)
您的可执行文件包含C运行时,它知道如何执行诸如获取环境,设置argv向量以及在调用{
index: {
mappings: {
image: {
_id: {
path: "image_id"
},
properties: {
caption: {
type: "string"
},
comments: {
properties: {
count: {
type: "integer"
}
}
},
creation_time: {
type: "date",
format: "dateOptionalTime"
},
is_tag_search: {
type: "boolean"
},
image_id: {
type: "string",
index: "not_analyzed"
},
likes: {
properties: {
count: {
type: "integer"
}
}
},
location: {
type: "geo_point",
lat_lon: true
},
logos: {
type: "string"
},
social_score: {
type: "float"
},
source: {
type: "string",
analyzer: "keyword_lowercase"
},
tags: {
type: "string",
analyzer: "tags",
fields: {
raw: {
type: "string",
index: "not_analyzed"
}
}
},
url: {
type: "string",
index: "no"
}
}
},
tag: {
_id: {
path: "tag_id"
},
properties: {
name: {
type: "string"
},
suggest: {
type: "completion",
analyzer: "simple",
payloads: true,
preserve_separators: true,
preserve_position_increments: true,
max_input_length: 50
},
tag_id: {
type: "string"
}
}
}
}
}
之后但在调用exit()
之前关闭所有打开的文件。
答案 3 :(得分:3)
正如其他海报所指出的那样,在编辑过程中有许多因素可能会影响最终的文件大小。
剖析你的具体例子比我愿意投入更多的工作,但我知道多年前的一个类似的例子,它可以帮助你理解一般问题,并引导你找到你寻求的具体答案
http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
这是使用GCC在C(而不是C ++)中完成的,查看ELF可执行文件(不是Windows EXE)的大小,但正如我所说,许多相同的问题都适用。在这种情况下,作者仅查看return 42;
在您阅读该文档后,请考虑打印到stdout
要比返回一个数字复杂得多。此外,由于您使用的是C ++和cout <<
,因此有许多代码隐藏在您没有编写的内容中,如果不查看该源代码,您无法真正了解它是如何实现的。
答案 4 :(得分:3)
人们一直在忽略/忘记在高级语言中创建的可执行文件需要引擎才能正常运行。例如,C ++引擎负责以下事项:
堆/堆栈管理
new,delete
时,您实际上并未访问操作系统功能局部变量内存管理
<强>类/模板强>
除此之外,您还必须链接您使用的所有内容:
<<
,你还需要更多它们才能使它工作......)您可以将C ++引擎视为操作系统中的小型操作系统
另一个空间被可执行格式(如PE)占用,并且代码对齐也增加了一些空间
当你把所有这些放在一起时,26KB就不再那么疯狂了
答案 5 :(得分:3)
编译器并非无所不能。
std::cout
是一个流对象,带有一组用于管理缓冲区的数据成员(分配它,将数据复制到它,当流被销毁时,释放它)。
operator<<
被实现为一个重载函数,它解释了它的参数,并且 - 当提供一个字符串时 - 将数据复制到缓冲区,其中一些逻辑可能在缓冲区满时刷新缓冲区。
std::endl
实际上是一个函数,它与流的所有版本operator<<()
合作 - 影响流所拥有的数据。具体来说,它将一个换行符插入到流缓冲区中,然后刷新缓冲区。
刷新流的缓冲区调用将数据从缓冲区复制到标准输出设备(例如屏幕)的其他函数。
以上所有内容都是std::cout<<"Hello World"<<std::endl
声明的作用。
此外,作为C ++程序,在调用main()
之前必须执行一定数量的代码。这包括检查程序是否使用命令行参数运行,创建诸如std::cout
,std::cerr
,std::cin
(还有其他)的流,确保这些流与相关设备(如终端)连接,或管道,或其他)。当main()
返回时,则需要释放所有创建的流(并刷新其缓冲区),以及类似的东西。
以上所有内容都涉及调用其他功能。为流创建缓冲区意味着必须分配缓冲区,并且在main()
返回后 - 释放。
C ++流的规范还涉及错误检查。 std::cout
缓冲区的分配可能会失败(例如,如果主机系统没有足够的可用内存)。标准输出设备可能会重定向到容量有限的文件 - 因此向其写入数据可能会失败。必须检查所有这些事情并妥善处理。
所有这些东西都将在这个26K可执行文件中(除非该代码在运行时库中)。
原则上,编译器可以识别程序没有使用其命令行参数(因此不包括管理命令行参数的代码),只写入std::cout
(所以不需要创建所有其他的在main()
之前的流并在main()
返回后释放它们),只使用两个重载版本的operator<<()
和一个流操纵器(因此链接器不需要包含所有其他成员函数的代码)流)。它还可能认识到语句将数据写入流并立即刷新缓冲区 - 从而消除std::cout
的缓冲区和管理它的所有代码。如果编译器可以读取程序员的想法(实际上很少有编译器可能会发现实际上不需要任何缓冲区,那么用户将永远不会运行带有重定向标准输出的程序等)并消除与所有这些事情相关的代码和数据结构。
那么,编译器如何识别所有这些东西都不需要?编译器是软件,因此他们必须对其输入(例如源文件)进行某种程度的分析。消除人类可能认为不必要的所有代码的分析是重要的 - 因此需要时间。如果编译器没有进行分析,可能链接器可能会进行分析。是否通过编译器或链接器完成消除不必要代码的分析是无关紧要的 - 这需要时间。潜在的重要时间。
程序员往往不耐烦。很少有程序员能够容忍一个简单的“你好世界”的构建过程。花了几秒钟的程序(也许他们会忍受一分钟,但不会多一点)。
这让编译器供应商做出了决定。他们可以让程序员设计和实现各种分析,以消除不需要的代码。这将增加数周 - 或者,如果他们在紧迫的截止日期前工作几个月 - 来实现,验证,验证并向客户(其他开发人员)发送有效的编译器。编译器编译时编译器会很慢。相反,供应商(及其开发人员)选择在他们的编译器中实现较少的分析,因此他们实际上可以将一个有效的编译器发送给将在合理时间内使用它的开发人员。这个编译器会在大多数程序员可以容忍的时间内生成一个可执行文件(例如,对于一个&#34; hello world&#34;程序,在一分钟之内)。那么如果可执行文件更大呢?它会工作。硬件(例如驱动器)相对便宜,并且开发人员的工作相对昂贵。
答案 6 :(得分:3)
这是一个非常古老的问题。它有明确的答案。最大的问题是,必须编写许多小的信息并进行许多小测试,以展示PE结构的不同方面。我试图跳过细节并描述基于Microsoft Visual Studio的问题的主要部分,我知道并使用多年。所有其他编译器大致相同,我想只需要使用其他一些编译器和链接器选项。
首先,我建议你在main
的第一行设置断点,开始调试并检查调试器的调用栈窗口。你会看到像
首先,理解这一点非常重要,主要不是第一个在程序中调用的函数。该计划的入口点为mainCRTStartup
,调用__tmainCRTStartup
,调用main
。
CRT启动代码可以做很多小事。有一点很容易理解:它使用GetCommandLineW
Windows API获取命令行并解析参数,然后使用参数调用main
。
要减小代码的大小,有两种常用方法:
如果使用“VS2013 x64 Native Tools命令提示符”(或某些关闭命令提示符)启动cmd.exe,这将非常有用。将在命令提示符内设置一些其他路径,您可以使用例如dumpbin.exe
实用程序。
如果您使用Multi-threaded DLL (/MD)
编译器选项,那么您将获得7K大型exe文件。 “dumpbin / imports HelloWorld.exe”将显示您的程序使用“MSVCR120.dll”和“KERNEL32.dll”。
删除CRT取决于您使用的c / cpp编译器版本(Visual Studio的版本),甚至取决于文件扩展名:.c
或.cpp
。我理解您的问题是用于理解问题的常见问题。所以我建议从最简单的情况开始,重命名.cpp
文件.c
和开头,并将代码修改为以下
#include <Windows.h>
int mainCRTStartup()
{
return 0;
}
现在可以看到
C:\Oleg\StackOverflow\HelloWorld\Release>dir HelloWorld.exe
Volume in drive C has no label.
Volume Serial Number is 4CF9-FADF
Directory of C:\Oleg\StackOverflow\HelloWorld\Release
21.06.2015 12:56 3.584 HelloWorld.exe
1 File(s) 3.584 bytes
0 Dir(s) 16.171.196.416 bytes free
C:\Oleg\StackOverflow\HelloWorld\Release>dumpbin HelloWorld.exe
Microsoft (R) COFF/PE Dumper Version 12.00.31101.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file HelloWorld.exe
File Type: EXECUTABLE IMAGE
Summary
1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text
可以添加链接器选项/MERGE:.rdata=.text以减小大小并删除一个部分
C:\Oleg\StackOverflow\HelloWorld\Release>dir HelloWorld.exe
Volume in drive C has no label.
Volume Serial Number is 4CF9-FADF
Directory of C:\Oleg\StackOverflow\HelloWorld\Release
21.06.2015 18:44 3.072 HelloWorld.exe
1 File(s) 3.072 bytes
0 Dir(s) 16.170.852.352 bytes free
C:\Oleg\StackOverflow\HelloWorld\Release>dumpbin HelloWorld.exe
Microsoft (R) COFF/PE Dumper Version 12.00.31101.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file HelloWorld.exe
File Type: EXECUTABLE IMAGE
Summary
1000 .data
1000 .reloc
1000 .rsrc
1000 .text
要拥有“Hello World”程序,我建议将代码修改为
#include <Windows.h>
int mainCRTStartup()
{
LPCTSTR pszString = TEXT("Hello world");
DWORD cbWritten;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pszString, lstrlen(pszString), &cbWritten, NULL);
return 0;
}
可以轻松验证代码是否有效,但仍然很小。
要从.cpp文件中删除CRT,我建议您按照以下步骤操作。首先,我们将使用以下HelloWorld.cpp
代码
#include <Windows.h>
int mainCRTStartup()
{
LPCTSTR pszString = TEXT("Hello world");
DWORD cbWritten;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), pszString, lstrlen(pszString), &cbWritten, NULL);
return 0;
}
重要的是要验证一些编译器和链接器选项并设置/删除某人。我在下面的图片中包含了设置:
最后一个屏幕显示我们删除了对我们不需要的默认库的绑定。编译器使用类似#pragma comment(lib, "some.lib")
的指令来注入一些库的使用。通过使用选项/NODEFAULTLIB
,我们删除了这些库,exe将按照我们的需要进行编译。
可以看到生成的HelloWorld.exe只有3K(3.072字节),并且只存在与一个KERNEL32.dll的依赖关系:
C:\Oleg\StackOverflow\HelloWorld\Release>dumpbin /imports HelloWorld.exe
Microsoft (R) COFF/PE Dumper Version 12.00.31101.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file HelloWorld.exe
File Type: EXECUTABLE IMAGE
Section contains the following imports:
KERNEL32.dll
402000 Import Address Table
402038 Import Name Table
0 time date stamp
0 Index of first forwarder reference
60B lstrlenW
5E0 WriteConsoleW
2C0 GetStdHandle
Summary
1000 .idata
1000 .reloc
1000 .rsrc
1000 .text
可以从here下载相应的Visual Studio 2013演示项目。需要从默认的“Debug”编译切换到“Release”并重建解决方案。一个人将使用长度为3K的HelloWorld.exe。
答案 7 :(得分:1)
这确实表明编写具有相同语义的程序是多么困难。
如果该流为<<std::endl
, good()
将刷新流。这意味着必须存在ostream
的整个错误处理代码。
此外,std::cout
可能会将streambuf
从其下方换出。编译器无法知道它实际上是STDOUT_FILENO
。它必须使用整个streambuf
中间层。