GCC编译调试入门——复习编译原理

g++使用

今天突然对while(cin>>a)很好奇,用到gcc来编译,然后尝试objdump反汇编,记录一下学习了什么新知识,然后复习大三上学习的编译原理,我好菜qwq。

C++的编译过程

一个完整的C++编译过程(例如g++ a.cpp生成可执行文件),总共包含以下四个过程:

编译预处理,也称预编译,可以使用命令g++ -E执行
编译,可以使用g++ -S执行
汇编,可以使用as 或者g++ -c执行
链接,可以使用g++ xxx.o xxx.so xxx.a执行

参考:https://zhuanlan.zhihu.com/p/151219726
我的代码

#include<iostream>
using namespace std;
int main()
{
	int a;
	int count=0;
	while(cin>>a)
	{
		count++;
	}
	return 0;
}

1、预编译
输入指令
g++ -E while_test.cpp -o test.ii
得到由while_test.cpp预编译以后的test.ii文件
在这里插入图片描述预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作的阶段主要处理#开始的预编译指令。预编译完成后,#include引入的内容 被全部复制进预编译文件中,除此之外,如果文件中有使用宏定义也会被替换处理。
这个预编译生成的文件很大,很多都看不懂QAQ,不知道是啥?
有一堆__extension__和extern。
经查阅应该是使用__extension__关键字告诉gcc不要抛出警告。

2、G++编译——C++语法错误检查
使用命令

g++ -S test.ii -o test.s

获得编程得到的汇编文件test.s

   .file   "while_test.cpp"
        .text
        .section        .rodata
        .type   _ZStL19piecewise_construct, @object
        .size   _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
        .zero   1
        .local  _ZStL8__ioinit
        .comm   _ZStL8__ioinit,1,1
        .text
        .globl  main
        .type   main, @function
main:
.LFB1493:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    %fs:40, %rax
        movq    %rax, -8(%rbp)
        xorl    %eax, %eax
        movl    $0, -12(%rbp)
.L3:
        leaq    -16(%rbp), %rax
        movq    %rax, %rsi
        leaq    _ZSt3cin(%rip), %rdi
        call    _ZNSirsERi@PLT
        movq    (%rax), %rdx
        subq    $24, %rdx
        movq    (%rdx), %rdx
             movq    (%rdx), %rdx
        leaq    _ZStL8__ioinit(%rip), %rsi
        movq    _ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
        movq    %rax, %rdi
        call    __cxa_atexit@PLT
.L8:
        nop
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1977:
        je      .L5
        call    __stack_chk_fail@PLT
.L5:
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1493:
        .size   main, .-main
        .type   _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1977:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        cmpl    $1, -4(%rbp)
        jne     .L8
     	 cmpl    $65535, -8(%rbp)
        jne     .L8
        leaq    _ZStL8__ioinit(%rip), %rdi
        call    _ZNSt8ios_base4InitC1Ev@PLT
        leaq    __dso_handle(%rip), %rdx
        leaq    _ZStL8__ioinit(%rip), %rsi
        movq    _ZNSt8ios_base4InitD1Ev@GOTPCREL(%rip), %rax
        movq    %rax, %rdi
        call    __cxa_atexit@PLT
.L8:
        nop
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE1977:
        .size   _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii
        .type   _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1978:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    $65535, %esi
        movl    $1, %edi
        call    _Z41__static_initialization_and_destruction_0ii
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
                .cfi_endproc
.LFE1978:
        .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
        .section        .init_array,"aw"
        .align 8
        .quad   _GLOBAL__sub_I_main
        .hidden __dso_handle
        .ident  "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
        .section        .note.GNU-stack,"",@progbits
        movl    %edi, -4(%rbp)      

3、g++ 汇编阶段:生成目标代码 .o文件

有两种方式:

使用 g++ 直接从源代码生成目标代码 g++ -c *.s -o *.o
使用汇编器从汇编代码生成目标代码 as *.s -o *.o

使用命令

g++ -c test.s -o test.o

获得的.o文件是一堆乱码不可读
也可以直接使用as *.s, 将执行汇编、链接过程生成可执行文件a.out, 可以像上面使用-o 选项指定输出文件的格式。

4、g++ 链接阶段:生成可执行文件;Windows下生成.exe

生成目标文件:

g++ test.cpp -c -o test.o
g++ main.cpp -c -o main.o 

链接生成可执行文件:

g++ main.o test.o -o a.out

我没有main文件,我的命令为

g++ test.o -o test.out

最后获得可执行文件test.out

在这里插入图片描述
好了到这里就完成了程序的编译链接生成可执行文件的过程啦!

objdump

这里我们来使用objdump来对.out文件进行反汇编

  1. -d:将代码段反汇编
  2. -S:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出-g,即需要调试信息。
  3. -C:将C++符号名逆向解析。
  4. -l:反汇编代码中插入源代码的文件名和行号。
  5. -j section:仅反汇编指定的section。可以有多个-j参数来选择多个section。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值