JoeChenzzz

导航

编译

1.编译过程

1.1预编译

  将程序中的头文件包含进代码中,并进行一些宏替换

gcc -E test.c -o test.i     //—E:预编译    .i文件为预编译后的文件

1.2编译和优化

  将用户写的代码翻译成汇编代码,生成汇编代码文件,汇编代码和机器操作码之间是一对一的关系

gcc -S test.i -o test.s     //—S:只进行编译而不进行汇编    .s文件为汇编代码文件
gcc -S test.c -o test.s     //也可以直接对test.c操作

1.3汇编

1)GNU使用汇编器as将汇编代码汇编成CPU可识别的二进制代码,生成目标文件,默认后缀为.o(windows下默认为.obj)

2)目标文件仅解析了文件内部的变量和函数,对所引用的在其他文件中或中的函数和变量还没有解析,所以还不可以执行

gcc -c test.s -o test.o     //—c:生成目标文件    .o文件为目标文件
gcc -c test.c -o test.o     //也可以直接对test.c操作

1.4链接

1)将所有的目标文件以某种方式链接起来,生成可执行文件,可执行文件的默认后缀为.out(windows下默认为.exe)

gcc test.o -o test          
gcc test.c -o test          //直接一步到位

2)函数库一般分为静态库动态库两种

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

4)动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时动态地加载库,一来这样可以减小执行文件地大小,二里更新库后程序也不用重新编译。动态库一般后缀名为”.so”。gcc在编译时默认使用动态库

1.5gcc和g++

1)gcc和g++的误区:gcc只能编译c代码,g++只能编译c++代码,其实二者都可以编译c或cpp文件,但是请注意:

  • 对于 .c和.cpp文件,gcc分别当做c和cpp文件编译,对于 .c和.cpp文件,g++则统一当做cpp文件编译
  • 在编译阶段,g++会调用gcc,在链接阶段,gcc不能自动和c++库链接,所以要先用gcc进行预编译、编译、汇编,再用g++进行链接,或者使用 gcc cfq.cpp -lstdc++ -o cfq
  • 为了统一起见,干脆编译/链接统统用g++了,这就给人一种错觉,好像cpp程序只能用g++似的

2)常用参数:

2.Makefile

2.1规则

1)许多程序在其makefile文件中将 all 指定为第一个目标,然后列出其他的all所依赖的目标。这个约定可以很清晰的指出当没有指定目标时makefile应尝试构建的默认目标。我们建议遵守这个约定

2.2变量

1)用户自定义变量:用户可以定义自己变量

2)预定义变量:Makefile中已经定义的变量

3)自动变量:为了Makefile看起来没那么冗长,用自动变量来代表目标文件和依赖文件

3.gdb调试

3.1常用命令

1)要是用gdb进行调试,在编译程序的时候必须加入-g选项,只有设置了-g选项,gcc才会向程序加入"锲子",GDB才能够利用这些锲子与程序交互

2)加载程序:

3)设置输入参数:

4)打印源代码内容:

list  1,20        //显示第一行到第二十行

5)设置断点:

6)多线程:

7)查看函数调用的栈帧:

frame:打印当前所处在的栈帧的简要信息

info frame:打印当前所处在的栈帧的详细信息

backtrace:打印当前全部栈帧的简要信息

frame N:切换到栈编号为N的上下文中

3.2core

1)core文件:程序崩溃后,产生“segmentation fault (core dumped)”的错误信息,这时会生成一个具有内存信息、寄存器状态、堆栈信息和调试信息的文件,名为core

2)发生core dumped的原因:

  • 内存访问越界 ,如:数组越界、字符串无\n结束符、字符串读写越界
  • 多线程程序中使用了线程不安全的函数,如不可重入函数
  • 多线程读写临界资源时未加锁保护
  • 非法指针,如:使用空指针(使用空指针也会崩的哦,亲测),使用野指针,使用空悬指针
  • 堆栈溢出

3)core文件的默认保存路径为对应的执行程序的同一目录,默认文件名为core,若要修改,则在 /proc/sys/kernel/core_pattern 中修改,此文件的默认内容为 core

echo "/home/coredump/core.%e.%p" >/proc/sys/kernel/core_pattern    //这样配置后,产生的core文件名中将带有崩溃的程序名以及它的进程ID,%e和%p会被替换成程序文件名以及进程ID,core文件将会放置到/home/coreddump下,注意:此目录必须是已存在文件系统的,不然报错;如果没写路径,直接是文件名,则保存在执行程序的同一目录下

  需要说明的是,在内核中还有一个与coredump相关的设置,就是/proc/sys/kernel/core_uses_pid。如果这个文件的内容被配置成1,那么即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID

  同时,在程序中使用chdir()函数更改了当前工作目录,core文件也会相应地存到那里

4)如何让系统生成core文件:

  •     使用 ulimit -c 查看core开关,如果为0表示关闭,不会生成core文件;
  •     使用 ulimit -c [filesize] 设置core文件大小,最小设为4,当最小设置为4之后才会生成core文件;

这里 file size 的单位是 blocks,可是这个 blocks 是多大呢?一般印象上是 512 字节,看了一下 bash 代码可知:

#define BLOCKSIZE(x)    (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
  •     使用 ulimit -c unlimited 设置core文件大小为不限制,这是常用的做法;

5)如何判断一个文件是core文件:

  • 看名字
  • core文件是ELF格式的文件,因此,可以通过readelf -h命令查看文件的头部信息:

6)查看core文件中的信息:gdb  可执行程序的名称   core文件的名称

posted on 2019-03-02 12:16  JoeChenzzz  阅读(345)  评论(0编辑  收藏  举报