通过阅读 gcc 输出来学习汇编

Posted

技术标签:

【中文标题】通过阅读 gcc 输出来学习汇编【英文标题】:learning assembly by reading gcc output 【发布时间】:2015-08-13 05:01:47 【问题描述】:

我试图通过阅读 GCC 生成的输出来理解程序集。这是我在 C++ 中的代码:

int main() 
    int x = 8;

我使用以下方法编译它:

g++ -g -Wa,-alh=source.s -masm=intel -fverbose-asm -O2 -g -Wall -c -fmessage-length=0 -o source.o "..\\source.cpp"

但是,即使使用 cmets,我也完全不了解生成的所有内容:

GAS LISTING C:\Users\Silkworm\AppData\Local\Temp\ccmDrbTs.s             page 1


   1                    .file   "source.cpp"
   2                    .intel_syntax noprefix
   3                 # GNU C++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 5.1.0 (x86_64-w64-mingw32)
   4                 #  compiled by GNU C version 5.1.0, GMP version 6.0.0, MPFR version 3.1.2-p11, MPC version 1.0.3
   5                 # GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
   6                 # options passed: 
   7                 # -iprefix C:/mingw-w64/x86_64-5.1.0-posix-seh-rt_v4-rev0/mingw64/bin/../lib/gcc/x86_64-w64-mingw3
   8                 # -D_REENTRANT ..\source.cpp -masm=intel -mtune=core2 -march=nocona
   9                 # -auxbase-strip source.o -g -g -O2 -Wall -fverbose-asm
  10                 # -fmessage-length=0
  11                 # options enabled:  -faggressive-loop-optimizations -falign-labels
  12                 # -fasynchronous-unwind-tables -fauto-inc-dec -fbranch-count-reg
  13                 # -fcaller-saves -fchkp-check-incomplete-type -fchkp-check-read
  14                 # -fchkp-check-write -fchkp-instrument-calls -fchkp-narrow-bounds
  15                 # -fchkp-optimize -fchkp-store-bounds -fchkp-use-static-bounds
  16                 # -fchkp-use-static-const-bounds -fchkp-use-wrappers
  17                 # -fcombine-stack-adjustments -fcommon -fcompare-elim -fcprop-registers
  18                 # -fcrossjumping -fcse-follow-jumps -fdefer-pop
  19                 # -fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively
  20                 # -fdwarf2-cfi-asm -fearly-inlining -feliminate-unused-debug-types
  21                 # -fexceptions -fexpensive-optimizations -fforward-propagate
  22                 # -ffunction-cse -fgcse -fgcse-lm -fgnu-runtime -fgnu-unique
  23                 # -fguess-branch-probability -fhoist-adjacent-loads -fident
  24                 # -fif-conversion -fif-conversion2 -findirect-inlining -finline
  25                 # -finline-atomics -finline-functions-called-once -finline-small-functions
  26                 # -fipa-cp -fipa-cp-alignment -fipa-icf -fipa-icf-functions
  27                 # -fipa-icf-variables -fipa-profile -fipa-pure-const -fipa-ra
  28                 # -fipa-reference -fipa-sra -fira-hoist-pressure -fira-share-save-slots
  29                 # -fira-share-spill-slots -fisolate-erroneous-paths-dereference -fivopts
  30                 # -fkeep-inline-dllexport -fkeep-static-consts -fleading-underscore
  31                 # -flifetime-dse -flra-remat -flto-odr-type-merging -fmath-errno
  32                 # -fmerge-constants -fmerge-debug-strings -fmove-loop-invariants
  33                 # -fomit-frame-pointer -foptimize-sibling-calls -foptimize-strlen
  34                 # -fpartial-inlining -fpeephole -fpeephole2 -fpic -fprefetch-loop-arrays
  35                 # -free -freg-struct-return -freorder-blocks -freorder-functions
  36                 # -frerun-cse-after-loop -fsched-critical-path-heuristic
  37                 # -fsched-dep-count-heuristic -fsched-group-heuristic -fsched-interblock
  38                 # -fsched-last-insn-heuristic -fsched-rank-heuristic -fsched-spec
  39                 # -fsched-spec-insn-heuristic -fsched-stalled-insns-dep -fschedule-fusion
  40                 # -fschedule-insns2 -fsemantic-interposition -fset-stack-executable
  41                 # -fshow-column -fshrink-wrap -fsigned-zeros -fsplit-ivs-in-unroller
  42                 # -fsplit-wide-types -fssa-phiopt -fstdarg-opt -fstrict-aliasing
  43                 # -fstrict-overflow -fstrict-volatile-bitfields -fsync-libcalls
  44                 # -fthread-jumps -ftoplevel-reorder -ftrapping-math -ftree-bit-ccp
  45                 # -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-coalesce-vars
  46                 # -ftree-copy-prop -ftree-copyrename -ftree-cselim -ftree-dce
  47                 # -ftree-dominator-opts -ftree-dse -ftree-forwprop -ftree-fre
  48                 # -ftree-loop-if-convert -ftree-loop-im -ftree-loop-ivcanon
  49                 # -ftree-loop-optimize -ftree-parallelize-loops= -ftree-phiprop -ftree-pre
  50                 # -ftree-pta -ftree-reassoc -ftree-scev-cprop -ftree-sink -ftree-slsr
  51                 # -ftree-sra -ftree-switch-conversion -ftree-tail-merge -ftree-ter
  52                 # -ftree-vrp -funit-at-a-time -funwind-tables -fvar-tracking
  53                 # -fvar-tracking-assignments -fverbose-asm -fzero-initialized-in-bss
  54                 # -m128bit-long-double -m64 -m80387 -maccumulate-outgoing-args
  55                 # -malign-double -malign-stringops -mcx16 -mfancy-math-387 -mfentry
  56                 # -mfp-ret-in-387 -mfxsr -mieee-fp -mlong-double-80 -mmmx -mms-bitfields
  57                 # -mno-sse4 -mpush-args -mred-zone -msse -msse2 -msse3 -mstack-arg-probe
GAS LISTING C:\Users\Silkworm\AppData\Local\Temp\ccmDrbTs.s             page 2


  58                 # -mvzeroupper
  59                
  60                    .text
  61                .Ltext0:
  62                    .cfi_sections   .debug_frame
  63                    .def    __main; .scl    2;  .type   32; .endef
  64                    .section    .text.startup,"x"
  65                    .p2align 4,,15
  66                    .globl  main
  67                    .def    main;   .scl    2;  .type   32; .endef
  68                    .seh_proc   main
  69                main:
  70                .LFB0:
  71                    .file 1 "../source.cpp"
   1:../source.cpp **** 
   2:../source.cpp **** int main() 
  72                    .loc 1 2 0
  73                    .cfi_startproc
  74 0000 4883EC28      sub rsp, 40  #,
  75                    .seh_stackalloc 40
  76                    .cfi_def_cfa_offset 48
  77                    .seh_endprologue
  78                    .loc 1 2 0
  79 0004 E8000000      call    __main   #
  79      00
  80                .LVL0:
   3:../source.cpp **** int x = 8;
   4:../source.cpp **** 
  81                    .loc 1 4 0
  82 0009 31C0          xor eax, eax     #
  83 000b 4883C428      add rsp, 40  #,
  84                    .cfi_def_cfa_offset 8
  85 000f C3            ret
  86                    .cfi_endproc
  87                .LFE0:
  88                    .seh_endproc
  89                    .text
  90                .Letext0:
  91                    .section    .debug_info,"dr"
  92                .Ldebug_info0:
  93 0000 CF000000      .long   0xcf
  94 0004 0400          .word   0x4
  95 0006 00000000      .secrel32   .Ldebug_abbrev0
  96 000a 08            .byte   0x8
  97 000b 01            .uleb128 0x1
  98 000c 474E5520      .ascii "GNU C++ 5.1.0 -masm=intel -mtune=core2 -march=nocona -g -g -O2 -fmessage-length=0\0"
  98      432B2B20 
  98      352E312E 
  98      30202D6D 
  98      61736D3D 
  99 005e 04            .byte   0x4
 100 005f 2E2E5C68      .ascii "..\\source.cpp\0"
 100      656C6C6F 
 100      776F726C 
 100      642E6370 
 100      7000
 101 0071 433A5C63      .ascii "C:\\cpp_workspace\\disam\\Debug\0"
GAS LISTING C:\Users\Silkworm\AppData\Local\Temp\ccmDrbTs.s             page 3


 101      70705F77 
 101      6F726B73 
 101      70616365 
 101      5C646973 
 102 008e 00000000      .secrel32   .Ldebug_ranges0+0
 103 0092 00000000      .quad   0
 103      00000000 
 104 009a 00000000      .secrel32   .Ldebug_line0
 105 009e 02            .uleb128 0x2
 106 009f 6D61696E      .ascii "main\0"
 106      00
 107 00a4 01            .byte   0x1
 108 00a5 02            .byte   0x2
 109 00a6 CB000000      .long   0xcb
 110 00aa 00000000      .quad   .LFB0
 110      00000000 
 111 00b2 10000000      .quad   .LFE0-.LFB0
 111      00000000 
 112 00ba 01            .uleb128 0x1
 113 00bb 9C            .byte   0x9c
 114 00bc CB000000      .long   0xcb
 115 00c0 03            .uleb128 0x3
 116 00c1 7800          .ascii "x\0"
 117 00c3 01            .byte   0x1
 118 00c4 03            .byte   0x3
 119 00c5 CB000000      .long   0xcb
 120 00c9 08            .byte   0x8
 121 00ca 00            .byte   0
 122 00cb 04            .uleb128 0x4
 123 00cc 04            .byte   0x4
 124 00cd 05            .byte   0x5
 125 00ce 696E7400      .ascii "int\0"
 126 00d2 00            .byte   0
 127                    .section    .debug_abbrev,"dr"
 128                .Ldebug_abbrev0:
 129 0000 01            .uleb128 0x1
 130 0001 11            .uleb128 0x11
 131 0002 01            .byte   0x1
 132 0003 25            .uleb128 0x25
 133 0004 08            .uleb128 0x8
 134 0005 13            .uleb128 0x13
 135 0006 0B            .uleb128 0xb
 136 0007 03            .uleb128 0x3
 137 0008 08            .uleb128 0x8
 138 0009 1B            .uleb128 0x1b
 139 000a 08            .uleb128 0x8
 140 000b 55            .uleb128 0x55
 141 000c 17            .uleb128 0x17
 142 000d 11            .uleb128 0x11
 143 000e 01            .uleb128 0x1
 144 000f 10            .uleb128 0x10
 145 0010 17            .uleb128 0x17
 146 0011 00            .byte   0
 147 0012 00            .byte   0
 148 0013 02            .uleb128 0x2
 149 0014 2E            .uleb128 0x2e
 150 0015 01            .byte   0x1
GAS LISTING C:\Users\Silkworm\AppData\Local\Temp\ccmDrbTs.s             page 4


 151 0016 3F            .uleb128 0x3f
 152 0017 19            .uleb128 0x19
 153 0018 03            .uleb128 0x3
 154 0019 08            .uleb128 0x8
 155 001a 3A            .uleb128 0x3a
 156 001b 0B            .uleb128 0xb
 157 001c 3B            .uleb128 0x3b
 158 001d 0B            .uleb128 0xb
 159 001e 49            .uleb128 0x49
 160 001f 13            .uleb128 0x13
 161 0020 11            .uleb128 0x11
 162 0021 01            .uleb128 0x1
 163 0022 12            .uleb128 0x12
 164 0023 07            .uleb128 0x7
 165 0024 40            .uleb128 0x40
 166 0025 18            .uleb128 0x18
 167 0026 9642          .uleb128 0x2116
 168 0028 19            .uleb128 0x19
 169 0029 01            .uleb128 0x1
 170 002a 13            .uleb128 0x13
 171 002b 00            .byte   0
 172 002c 00            .byte   0
 173 002d 03            .uleb128 0x3
 174 002e 34            .uleb128 0x34
 175 002f 00            .byte   0
 176 0030 03            .uleb128 0x3
 177 0031 08            .uleb128 0x8
 178 0032 3A            .uleb128 0x3a
 179 0033 0B            .uleb128 0xb
 180 0034 3B            .uleb128 0x3b
 181 0035 0B            .uleb128 0xb
 182 0036 49            .uleb128 0x49
 183 0037 13            .uleb128 0x13
 184 0038 1C            .uleb128 0x1c
 185 0039 0B            .uleb128 0xb
 186 003a 00            .byte   0
 187 003b 00            .byte   0
 188 003c 04            .uleb128 0x4
 189 003d 24            .uleb128 0x24
 190 003e 00            .byte   0
 191 003f 0B            .uleb128 0xb
 192 0040 0B            .uleb128 0xb
 193 0041 3E            .uleb128 0x3e
 194 0042 0B            .uleb128 0xb
 195 0043 03            .uleb128 0x3
 196 0044 08            .uleb128 0x8
 197 0045 00            .byte   0
 198 0046 00            .byte   0
 199 0047 00            .byte   0
 200                    .section    .debug_aranges,"dr"
 201 0000 2C000000      .long   0x2c
 202 0004 0200          .word   0x2
 203 0006 00000000      .secrel32   .Ldebug_info0
 204 000a 08            .byte   0x8
 205 000b 00            .byte   0
 206 000c 0000          .word   0
 207 000e 0000          .word   0
GAS LISTING C:\Users\Silkworm\AppData\Local\Temp\ccmDrbTs.s             page 5


 208 0010 00000000      .quad   .LFB0
 208      00000000 
 209 0018 10000000      .quad   .LFE0-.LFB0
 209      00000000 
 210 0020 00000000      .quad   0
 210      00000000 
 211 0028 00000000      .quad   0
 211      00000000 
 212                    .section    .debug_ranges,"dr"
 213                .Ldebug_ranges0:
 214 0000 00000000      .quad   .LFB0
 214      00000000 
 215 0008 10000000      .quad   .LFE0
 215      00000000 
 216 0010 00000000      .quad   0
 216      00000000 
 217 0018 00000000      .quad   0
 217      00000000 
 218                    .section    .debug_line,"dr"
 219                .Ldebug_line0:
 220 0000 41000000      .section    .debug_str,"dr"
 220      02002800 
 220      00000101 
 220      FB0E0D00 
 220      01010101 
 221                    .ident  "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 5.1.0"

这里没有我学到的一条指令,比如 movl、pop,也没有像 %eax 之类的寄存器或类似的东西。这与我在网上遇到的例子完全不同。我怎么理解这个。

【问题讨论】:

总结:这可能不是学习汇编的方法: 您的变量未使用。尝试以某种方式输出它。 一般来说,编译器生成的汇编代码与手动编写的汇编代码相比可能没有那么简单——有几个因素(如代码优化)起作用。要使推送、弹出指令可见,请尝试添加一个简单的函数并从 main 调用它。 一个什么都不做的程序不能指望有任何清楚地实现什么都不做的汇编指令。真的。查看编译器输出的想法还不错,但是您需要以更明智的方式进行处理。例如。从main 中的一个简单函数调用开始。请记住,编译器通常会添加大量样板代码,这对于最小的小程序来说没有意义。 我个人会使用编译C代码而不是C++的结果。 【参考方案1】:

正如@user2864740 所提到的,这不是学习汇编的最佳方式,但是您可以学习和了解不同的编译器如何将 C/C++ 转换为汇编以及它们如何优化您的代码。

在您的示例中,您不会看到任何有趣的学习内容,因为您的代码不包含任何功能,而且您还通过优化 (-O2) 对其进行编译。

    如果您想查看以易于理解的方式反映您编写的内容的汇编代码,请不要使用优化 (-O0)。 请注意,您选择了“intel”汇编代码语法,还有 AT&T 代码语法 (check here)。如果您想查看 AT&T 风格,请从编译行中删除 -masm=intel

例如,尝试构建以下代码:

int main()

 int x = 8;
 int y = 18;
 int z = x + y;

 return z;

没有优化你会得到类似的东西:

  35                main:
  36                .LFB2:
  37                    .file 1 "assm.cpp"
   1:assm.cpp      **** int main()
  38                    .loc 1 1 0
  39 0000 55            push    %rbp    #
  40                .LCFI0:
  41 0001 4889E5        mov %rbp, %rsp  #,
  42                .LCFI1:
  43                .LBB2:
   2:assm.cpp      ****     
   3:assm.cpp      ****      int x = 8;
  44                    .loc 1 3 0
  45 0004 C745F408      mov DWORD PTR [%rbp-12], 8  # x,
  45      000000
   4:assm.cpp      ****      int y = 18;
  46                    .loc 1 4 0
  47 000b C745F812      mov DWORD PTR [%rbp-8], 18  # y,
  47      000000
GAS LISTING /tmp/ccHUnQdo.s            page 2


   5:assm.cpp      ****      int z = x + y;
  48                    .loc 1 5 0
  49 0012 8B45F8        mov %eax, DWORD PTR [%rbp-8]    # y, y
  50 0015 0345F4        add %eax, DWORD PTR [%rbp-12]   # tmp60, x
  51 0018 8945FC        mov DWORD PTR [%rbp-4], %eax    # z, tmp60
   6:assm.cpp      ****     
   7:assm.cpp      ****      return z;
  52                    .loc 1 7 0
  53 001b 8B45FC        mov %eax, DWORD PTR [%rbp-4]    # D.2339, z
  54                .LBE2:
   8:assm.cpp      ****     
  55                    .loc 1 8 0
  56 001e C9            leave
  57 001f C3            ret

您可以看到局部变量在堆栈上(RBP 用于访问它们)并且编译器为它们分配了 12 个字节 (x,y,z) => 在我的机器上 sizeof(int) 是 4 个字节。 RBP 指向堆栈的末尾,x 首先在堆栈上分配,所以为了访问它,编译器使用“RBP-12”(y 是堆栈上的第二个,所以它由“RBP-8”访问,所以在)。方括号表示内存访问,括号中的值表示地址。“DWORD PTR”表示内存访问大小为“双字”,即4字节(字=16位=2字节)。

使用 -O2 优化,编译器优化所有代码并立即返回 26(如果 32 位足以保存该值而不会丢失数据,则返回值通常放在 EAX 中):

  48                main:
  49                .LFB2:
  50                    .file 1 "assm.cpp"
   1:assm.cpp      **** int main()
  51                    .loc 1 1 0
   2:assm.cpp      ****     
GAS LISTING /tmp/ccZvidrN.s            page 2


   3:assm.cpp      ****      int x = 8;
   4:assm.cpp      ****      int y = 18;
   5:assm.cpp      ****      int z = x + y;
   6:assm.cpp      ****     
   7:assm.cpp      ****      return z;
   8:assm.cpp      ****     
  52                    .loc 1 8 0
  53 0000 B81A0000      mov %eax, 26    # <result>,
  53      00
  54 0005 C3            ret

【讨论】:

【参考方案2】:

您的程序实际上并没有做任何事情;局部变量 x 未使用,已被编译器删除。大部分汇编代码是调试信息,其余的与调用主函数必须做什么有关。

不过你应该能认出这条线:

xor eax, eax

您的主函数隐式返回零。该值在 eax 寄存器中返回,因此该行将零放入 eax。

【讨论】:

以上是关于通过阅读 gcc 输出来学习汇编的主要内容,如果未能解决你的问题,请参考以下文章

20145317 《信息安全系统设计基础》第5周学习总结

如何使用 gcc 生成可以用 nasm 编译的汇编代码 [重复]

20145336张子扬 《信息安全系统设计基础》第5周学习总结

[翻译] GCC 内联汇编 HOWTO

转贴GCC内联汇编基础

2017-2018-1 20155208 《信息安全系统设计基础》第五周学习总结