• 【Linux编程基础】


    Linux之编译器、调试器使用

    一.编译器gcc/g++的使用

    1.预处理阶段

    预处理的功能

    1. 进行宏替换
    2. 解决条件编译
    3. 包含头文件
    4. 去注释
    #include 
      2 
      3 
      4 int AddToTop(int top)
      5 {
      6     int res = 0;
      7     int i = 0;
      8     for(i = 0; i <= top; i++ )
      9     {
     10         res += i;
     11     }
     12 
     13     return res;
     14 }
     15 
     16 #define _tzx 1
     17                                                                                                                                                                     
     18 #ifdef _tzx
     19 int a=3;
     20 #endif
     21 
     22 #define B 3
     23 
     24 int main()
     25 {
     26   int b = B;
     27   printf("%d\n",b);
     28 
     29   printf("%d\n",a);
     30     int top = 100;
     31     //返回1到n的和
     32     int result = AddToTop(top);
     33 
     34     printf("result: %d\n", result);
     35 
     36     printf("hello 1\n");
     37     printf("hello 2\n");
     38     printf("hello 3\n");
     39     printf("hello 4\n");
     40     return 0;                                                                                                                                                       
     41 }
    
    
    
    • 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

    最终形成一个.i的文件

    Linux命令

    gcc -E test.c -o test.i
    
    • 1

    test.i文件内容:

    1 # 1 "test.c"                                                                                                                                                        
      2 # 1 ""
      3 # 1 ""
      4 # 1 "/usr/include/stdc-predef.h" 1 3 4
      5 # 1 "" 2
      6 # 1 "test.c"
      7 # 1 "/usr/include/stdio.h" 1 3 4
      8 # 27 "/usr/include/stdio.h" 3 4
      9 # 1 "/usr/include/features.h" 1 3 4
     10 # 375 "/usr/include/features.h" 3 4
     11 # 1 "/usr/include/sys/cdefs.h" 1 3 4
     12 # 392 "/usr/include/sys/cdefs.h" 3 4
     13 # 1 "/usr/include/bits/wordsize.h" 1 3 4
     14 # 393 "/usr/include/sys/cdefs.h" 2 3 4
     15 # 376 "/usr/include/features.h" 2 3 4
     16 # 399 "/usr/include/features.h" 3 4
     17 # 1 "/usr/include/gnu/stubs.h" 1 3 4
     18 # 10 "/usr/include/gnu/stubs.h" 3 4
     19 # 1 "/usr/include/gnu/stubs-64.h" 1 3 4
     20 # 11 "/usr/include/gnu/stubs.h" 2 3 4
     21 # 400 "/usr/include/features.h" 2 3 4
     22 # 28 "/usr/include/stdio.h" 2 3 4
     23 
     24 
     25 
     26 
     27 
     28 # 1 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 1 3 4
     29 # 212 "/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include/stddef.h" 3 4
     30 typedef long unsigned int size_t;
     31 # 34 "/usr/include/stdio.h" 2 3 4
     32 
     33 # 1 "/usr/include/bits/types.h" 1 3 4
     34 # 27 "/usr/include/bits/types.h" 3 4
     35 # 1 "/usr/include/bits/wordsize.h" 1 3 4
     36 # 28 "/usr/include/bits/types.h" 2 3 4
     37
     38 
     39 typedef unsigned char __u_char;
     40 typedef unsigned short int __u_short;
     41 typedef unsigned int __u_int;
     42 typedef unsigned long int __u_long;
     43 
     44 
     45 typedef signed char __int8_t;
     46 typedef unsigned char __uint8_t;
     47 typedef signed short int __int16_t;
     48 typedef unsigned short int __uint16_t;
     49 typedef signed int __int32_t;
     50 typedef unsigned int __uint32_t;
     51 
     52 typedef signed long int __int64_t;
     53 typedef unsigned long int __uint64_t;
     
    
    // 此处省略一堆头文件内容
    
    840 int AddToTop(int top)                                                                                                                                               
    841 {
    842     int res = 0;
    843     int i = 0;
    844     for(i = 0; i <= top; i++ )
    845     {
    846         res += i;
    847     }
    848 
    849     return res;
    850 }
    851 
    852 
    853 
    854 
    855 int a=3;
    856 
    857 
    858 
    859 
    860 int main()
    861 {
    862   int b = 3;
    863   printf("%d\n",b);
    864 
    865   printf("%d\n",a);
    866     int top = 100;
    867 
    868     int result = AddToTop(top);
    869 
    870     printf("result: %d\n", result);
    871 
    872     printf("hello 1\n");
    873     printf("hello 2\n");
    874     printf("hello 3\n");
    875     printf("hello 4\n");
    876     return 0;
    877 }  
    
    //序号是linux的vim编辑器自带的
    
    
    • 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

    我们可以看到宏替换已经完成,条件编译也自动完成了,同时注释也不在了。

    2.编译阶段(生成汇编代码)

    gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查
    无误后,gcc 把代码翻译成汇编语言。

    Linux命令

    gcc -S test.i -o test.s
    
    • 1

    test.s内容:

    	.file	"test.c"
    	.text
    	.globl	AddToTop
    	.type	AddToTop, @function
    AddToTop:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	movl	%edi, -20(%rbp)
    	movl	$0, -4(%rbp)
    	movl	$0, -8(%rbp)
    	movl	$0, -8(%rbp)
    	jmp	.L2
    .L3:
    	movl	-8(%rbp), %eax
    	addl	%eax, -4(%rbp)
    	addl	$1, -8(%rbp)
    .L2:
    	movl	-8(%rbp), %eax
    	cmpl	-20(%rbp), %eax
    	jle	.L3
    	movl	-4(%rbp), %eax
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	AddToTop, .-AddToTop
    	.globl	a
    	.data
    	.align 4
    	.type	a, @object
    	.size	a, 4
    a:
    	.long	3
    	.section	.rodata
    .LC0:
    	.string	"%d\n"
    .LC1:
    	.string	"result: %d\n"
    .LC2:
    	.string	"hello 1"
    .LC3:
    	.string	"hello 2"
    .LC4:
    	.string	"hello 3"
    .LC5:
    	.string	"hello 4"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.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	$3, -4(%rbp)
    	movl	-4(%rbp), %eax
    	movl	%eax, %esi
    	movl	$.LC0, %edi
    	movl	$0, %eax
    	call	printf
    	movl	a(%rip), %eax
    	movl	%eax, %esi
    	movl	$.LC0, %edi
    	movl	$0, %eax
    	call	printf
    	movl	$100, -8(%rbp)
    	movl	-8(%rbp), %eax
    	movl	%eax, %edi
    	call	AddToTop
    	movl	%eax, -12(%rbp)
    	movl	-12(%rbp), %eax
    	movl	%eax, %esi
    	movl	$.LC1, %edi
    	movl	$0, %eax
    	call	printf
    	movl	$.LC2, %edi
    	call	puts
    	movl	$.LC3, %edi
    	call	puts
    	movl	$.LC4, %edi
    	call	puts
    	movl	$.LC5, %edi
    	call	puts
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
    	.section	.note.GNU-stack,"",@progbits
    [tzx@VM-20-3-centos code]$ 
    [tzx@VM-20-3-centos code]$ cat test.s
    	.file	"test.c"
    	.text
    	.globl	AddToTop
    	.type	AddToTop, @function
    AddToTop:
    .LFB0:
    	.cfi_startproc
    	pushq	%rbp
    	.cfi_def_cfa_offset 16
    	.cfi_offset 6, -16
    	movq	%rsp, %rbp
    	.cfi_def_cfa_register 6
    	movl	%edi, -20(%rbp)
    	movl	$0, -4(%rbp)
    	movl	$0, -8(%rbp)
    	movl	$0, -8(%rbp)
    	jmp	.L2
    .L3:
    	movl	-8(%rbp), %eax
    	addl	%eax, -4(%rbp)
    	addl	$1, -8(%rbp)
    .L2:
    	movl	-8(%rbp), %eax
    	cmpl	-20(%rbp), %eax
    	jle	.L3
    	movl	-4(%rbp), %eax
    	popq	%rbp
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE0:
    	.size	AddToTop, .-AddToTop
    	.globl	a
    	.data
    	.align 4
    	.type	a, @object
    	.size	a, 4
    a:
    	.long	3
    	.section	.rodata
    .LC0:
    	.string	"%d\n"
    .LC1:
    	.string	"result: %d\n"
    .LC2:
    	.string	"hello 1"
    .LC3:
    	.string	"hello 2"
    .LC4:
    	.string	"hello 3"
    .LC5:
    	.string	"hello 4"
    	.text
    	.globl	main
    	.type	main, @function
    main:
    .LFB1:
    	.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	$3, -4(%rbp)
    	movl	-4(%rbp), %eax
    	movl	%eax, %esi
    	movl	$.LC0, %edi
    	movl	$0, %eax
    	call	printf
    	movl	a(%rip), %eax
    	movl	%eax, %esi
    	movl	$.LC0, %edi
    	movl	$0, %eax
    	call	printf
    	movl	$100, -8(%rbp)
    	movl	-8(%rbp), %eax
    	movl	%eax, %edi
    	call	AddToTop
    	movl	%eax, -12(%rbp)
    	movl	-12(%rbp), %eax
    	movl	%eax, %esi
    	movl	$.LC1, %edi
    	movl	$0, %eax
    	call	printf
    	movl	$.LC2, %edi
    	call	puts
    	movl	$.LC3, %edi
    	call	puts
    	movl	$.LC4, %edi
    	call	puts
    	movl	$.LC5, %edi
    	call	puts
    	movl	$0, %eax
    	leave
    	.cfi_def_cfa 7, 8
    	ret
    	.cfi_endproc
    .LFE1:
    	.size	main, .-main
    	.ident	"GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-44)"
    	.section	.note.GNU-stack,"",@progbits
    
    
    • 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
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207

    3.汇编(生成机器可识别代码)

    Linux命令

    gcc -c test.s -o test.o
    
    • 1

    生成的是二进制代码,vim编辑器就无法识别了,得用专门的二进制查看器。

    4.链接(生成可执行文件)

    系统把这些库函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
    系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函
    数“printf”了,而这也就是链接的作用

    Linux命令

    gcc  test.o -o test.o
    
    • 1

    函数库

    静态库

    静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也
    就不再需要库文件了。其后缀名一般为“.a”

    动态库

    动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时
    链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态
    库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件 。

    gcc的选项

    -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面
    -S 编译到汇编语言不进行汇编和链接
    -c 编译到目标代码
    -o 文件输出到 文件
    -static 此选项对生成的文件采用静态链接
    -g 生成调试信息。GNU 调试器可利用该信息。
    -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.
    -O0
    -O1
    -O2
    -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
    -w 不生成任何警告信息。
    -Wall 生成所有警告信息。
    -g gcc/g++出来的二进制程序,默认是release模式,-g可改为debug模式
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    二.调试器gdb的使用

    gdb选项

    list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
    list/l 函数名:列出某个函数的源代码。
    r或run:运行程序。
    n 或 next:单条执行。
    s或step:进入函数调用
    break(b) 行号:在某一行设置断点
    break 函数名:在某个函数开头设置断点
    info break :查看断点信息。
    finish:执行到当前函数返回,然后挺下来等待命令
    print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
    p 变量:打印变量值。
    set var:修改变量的值
    continue(或c):从当前位置开始连续而非单步执行程序
    run(或r):从开始连续而非单步执行程序
    delete breakpoints:删除所有断点
    delete breakpoints n:删除序号为n的断点
    disable breakpoints:禁用断点
    enable breakpoints:启用断点
    info(或i) breakpoints:参看当前设置了哪些断点
    display 变量名:跟踪查看一个变量,每次停下来都显示它的值
    undisplay:取消对先前设置的那些变量的跟踪
    until X行号:跳至X行
    breaktrace(或bt):查看各级函数调用及参数
    info(i) locals:查看当前栈帧局部变量的值
    quit:退出gdb
    
    • 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

    Linux命令

    gcc -o test test.c -g
    gdb test
    
    • 1
    • 2

    list

    img

    run/r

    img

    b和info b

    b:打断点,r会执行到断点处

    info:查看断点

    img

    print(p)

    查看p的值

    img

    n(单步执行)

    img

    finish

    有断点时,遇到断点还是会停,没有就自动执行完该函数体。

    img

    display

    img

    bt

    img

    info locals

    img

    disable/enable breakpoints

    img

  • 相关阅读:
    T2T-ViT:更多的局部结构信息,更高效的主干网络 | ICCV 2021
    QT+OSG/osgEarth编译之四十五:osgViewer+Qt编译(一套代码、一套框架,跨平台编译,版本:OSG-3.6.5核心库osgViewer)
    【BERT-多标签文本分类实战】之二——BERT的地位与名词术语解释
    SQL基本语句
    【毕业设计】基于情感分析的网络舆情热点分析系统
    系统架构设计师(第二版)学习笔记----软件工程
    JavaScript 中常用的排序
    避免风险,亚马逊、沃尔玛、阿里国际站选择什么样的测评方式最安全?
    JavaAPI操作HBase-Day2
    【Intel CVPR 2024】通过图像扩散模型生成高质量360度场景,只需要一个语言模型
  • 原文地址:https://blog.csdn.net/m0_52882232/article/details/126541155