美文网首页
《an introduction to gcc》阅读笔记

《an introduction to gcc》阅读笔记

作者: 老杜振熙 | 来源:发表于2021-08-10 19:19 被阅读0次

    title: an_introduction_to_gcc.md
    date: 2021-08-09 20:42:04
    tags: gcc


    Convention

    • compilation: 从源代码到机器码的所有过程的总称
    • include path: 头文件搜索路径
    • liarary search path(或者link path): 库文件搜索路径

    Compiling a C program

    警告相关

    • -Wall: 开启所有常用的编译警告, 推荐任何情况下都加上该option。当有警告信息输出时,信息的格式为file:row-number:column-number:message

    Compiling files independently

    In general, linking is faster than compilation—in a large project with many source files, recompiling only those that have been modified can make a significant saving. The process of recompiling only the modified files in a project can be automated using GNU Make

    • 意义: 避免了每一次都从头开始进行全部的编译
    • object file: 也是机器码,只不过任何其他文件中的function或者variable的地址都被留空(left undefined)
    • -c: 为某个源文件生成object file, 例如gcc -Wall -c main.c会生成main.o

    Linking with external libraries

    • /tmp/xxx.o ... undefined reference: 出现了链接错误,这里的/tmp/xxx.o就是编译器自动生成的临时object file。(xxx.o这个名字是我自己瞎取的)
    • -lNAME: 让链接器尝试从静态库libNAME.a中获取有用的符号

    Compilation options

    Setting search paths

    Note that you should never place the absolute paths of header files in #include statements in your source code, as this will prevent the program from compiling on other systems.

    • -I: 增加include path, 实际上就是影响了INCLUDE_PATH这个变量的值
    • -L: 增加library search path
    • environment variable: 也可以通过在shell中修改C_INCLUDE_PATH, CPLUS_INCLUDE_PATH, LIBRARY_PATH这几个变量去增添搜索路径
    • 同时指定多个路径:
      • command line: 例如-I. -I/opt/gdbm-1.8.3/include -I/net/include
      • environment variable: 例如C_INCLUDE_PATH=.:/opt/gdbm-1.8.3/include:/net/include, 用:进行分隔
      • 其实,如果不想写了完整的CMakeLists.txt之后再用compile_commands.json实现vim的跳转的话,可以事先配置一个环境变量CPLUS_INCLUDE_PATH,加入需要搜索的路径,然后export CPLUS_INCLUDE_PATH,vim(clangd)就知道需要在哪里搜索头文件了。
    • 路径的搜索顺序:先搜索通过-I-L指定的路径;再搜索通过environment variable指定的路径;再搜索默认路径;

    Shared libraries and static libraries

    因为链接一个动态库可以使得可执行文件的体积更小,并且对动态库进行版本更新不会影响到使用它的可执行文件(只要接口不变),所以,只要有可能,GCC就会默认使用动态链接

    • default: 例如,如果GCC同时搜索到了libgdbm.alibgdbm.so,而编译时使用的是-lgdbm,那么GCC默认链接的是libgdbm.so
    • 增添动态库搜索路径:1. 设置环境变量LD_LIBRARY_PATH
    • -static: 强制GCC仅使用静态链接

    C language standards

    By default, gcc compiles programs using the GNU dialect of the C language, referred to as GNU C. This dialect incorporates the official ANSI/ISO standard for the C language with several useful GNU extensions, such as nested functions and variable-size arrays.

    For reference, the non-standard keywords and macros defined by the GNU C extensions are asm, inline, typeof, unix and vax

    • -ansi: 禁用掉GNU C中对于ANSI/ISO C标准的扩展,避免一些ANSI/ISO标准的C程序在GCC上进行编译时可能出现的不兼容的情况
      • 注意-ansi其实就是-std=c89的同义词
    • -pedantic: 当和-ansi结合的时候,会严格执行ANSI/ISO标准,禁用掉任何GNU C的扩展(真的非常严格)
      • 举个例子,GNU C的变长数组,实际上是对ANSI/ISO的后向兼容扩展,其他的标准C程序不会因为GNU C提供了变长数组的支持就无法在GNU C下编译。所以,即使加上了-ansi,照样是能够编译的;但如果再加上了-pedantic,编译器就会迂腐的照搬标准,程序就编译不了了
      • 作为对比,类似于asm这样的变量,在GNU C下是预先定义好了的,那么这样的程序,虽然在ANSI/ISO中可以编译,但是在GNU C中反而就编译不了了,无法后向兼容。

    Additional warning options

    • -W: 通常和-Wall一起使用,报告一些常见的潜在问题。(比如判断一个无符号数的正负性)
    • -Wconversion: 隐式转换可能出现的问题
    • -Wshadow: 定义了和外部空间同名的局部变量
    • -Wcast-qual: 强制去除了const这样的修饰符(qualifier)
    • -Werror: 强制编译器,只要遇到warn,就将其转换为error,使得编译终止

    Using the preprocessor

    Some macros are automatically defined by the compiler—these typically use a reserved namespace beginning with a double-underscore prefix ‘__’.

    • -DName: 利用command line定义一个宏,宏名是Name, 值为1
    • -DName="2+4": 利用command line定义一个宏,宏名是Name, 值为2+4
    • -DName="": 利用command line定义一个宏,宏名是Name, 值为空,但依旧已被定义
    • cpp -dM /dev/null: 展示GCC预定义了哪些macro。/dev/null的意思是分析这个空文件,因此只输出GCC预定义的macro
    • -E: 在stdout中输出经过预处理器处理之后的文件内容. (The preprocessor also inserts lines recording the source file and line numbers in the form # line-number "source-file", to aid in debugging and allow the compiler to issue error messages referring to this information.)
    • -save-temps: 保留预处理后的xxx.i(或者xxx.ii)源文件,编译后的xxx.s汇编代码文件,汇编之后的xxx.o可重定位目标文件。 i是C代码,ii是C++代码

    Compiling for debugging

    The debug option(-g) works by storing the names of functions and variables (and all the references to them), with their corresponding source code line-numbers, in a symbol table in object files and executables.

    本章仅对gdb进行了简单的阐述,详细的学习,需要阅读:《Debugging with GDB: The GNU Source-Level Debugger》

    • $ ulimit -c: 显示系统当前允许产生的core文件的最大大小
    • $ ulimit -c unlimited: 设置core文件大小无限制
      • 设置完毕后,后续执行程序时,如果崩掉,就会生成core文件
    • gdb EXECUTABLE-FILE CORE-FILE: 开始调试。(可执行文件和core文件都必须提供)
    #include <stdio.h>
    
    int deref_nullptr(int *p){
        int x = *p; // 这里有问题
        return x;
    }
    
    int main(int argc, const char** argv) {
        int *p = NULL;
        int x = deref_nullptr(p);
        printf("output is %d\n", x);
        return 0;
    }
    
    # 例子
    # print 打印变量的值
    # backtrace 打印当前状态下的调用栈
    $ gdb main core
    GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
    Copyright (C) 2020 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    Type "show copying" and "show warranty" for details.
    This GDB was configured as "x86_64-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
        <http://www.gnu.org/software/gdb/documentation/>.
    
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from main...
    [New LWP 1195]
    Core was generated by `./main'.
    Program terminated with signal SIGSEGV, Segmentation fault.
    #0  0x0000556e0426c159 in deref_nullptr (p=0x0) at ./gdb_test.cpp:4
    4           int x = *p;
    (gdb) print p
    $1 = (int *) 0x0
    (gdb) backtrace
    #0  0x00005555ef33a159 in deref_nullptr (p=0x0) at ./gdb_test.cpp:4
    #1  0x00005555ef33a18a in main (argc=1, argv=0x7ffd5ed3ee78) at ./gdb_test.cpp:10
    (gdb)
    
    

    Compiling with optimization

    Source-level optimization

    • common subexpression elimination: 利用临时变量存储一些中间值,从而减少运算
    • function inlining

    Optimization level

    optimizations may not necessarily make a program faster in every case.

    从0到3:

    • -O0: 默认级别。编译器不执行任何优化,也不进行指令重排。适合于debug
    • -O1: 执行一些常用的优化手段,但没有speed-space tradeoff以及指令重排
    • -O2: 除了O1的手段之后,还加入了指令重排。此外,该级别是最时候发布的级别
    • -O3: 编译时间最久。可能会增加最终的可执行文件的体积
    • -Os: 生成体积最小的可执行文件

    Compiling a C++ program

    永远遵守一个规定:C++代码使用g++,而C代码使用gcc

    explicit template instantiation

    • -fno-implicit-templates: 默认情况下,在编译过程中,每当使用到了一个模板,编译器对其进行隐式的具现化,而该option的作用就是禁止这个行为。程序中所有需要使用的模板具现化类型,会在另一个显示具现化文件中给出。这样做的好处是,所有模板的具现化类型都只有一个存在

    Platform-specific options

    Code produced with a specific ‘-march=CPU’ option will be faster but will not run on other processors in the x86 family.

    -m开头的option都是和平台特定的选项

    • -march=: 指定编译为哪一种特定的处理器指令格式。会更快,但是其他处理器型号就运行不了了
    • -m32: 生成32位程序(默认是64位)

    Compiler-related tools

    gcovgprof不想看了,先放一放

    Creating a library with the GNU archiver

    • ar cr <library-name> <object-file1 object-file2 ...>: 生成静态库文件,cr的意思是create and replace
      • ar t <library-name>: 展示一个静态库中包含有哪些object file

    Examining compiled flags

    • file: 检测executable file或者object file的一些flag,比如链接类型,LSB还是MSB,在哪类平台上进行编译的,等等;
    • nm: 获取可执行文件或者object file的符号表
      • 当第2列为"T"时,说明对应的函数是已经被定义了的;反之如果是"U",则说明没有定义
      • A complete explanation of the output of nm can be found in the GNU Binutils manual.
    • ldd: 明确可执行文件需要依赖于哪些动态库
    # nm 例子
    $ g++ -Wall -g -o ./main ./simple.cpp
    $ nm main
    0000000000003d90 d _DYNAMIC
    0000000000003f90 d _GLOBAL_OFFSET_TABLE_
    0000000000001238 t _GLOBAL__sub_I_main
    0000000000002000 R _IO_stdin_used
                     w _ITM_deregisterTMCloneTable
                     w _ITM_registerTMCloneTable
    00000000000011eb t _Z41__static_initialization_and_destruction_0ii
                     U _ZNSolsEPFRSoS_E@@GLIBCXX_3.4
                     U _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
                     U _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
    0000000000004040 B _ZSt4cout@@GLIBCXX_3.4
                     U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@@GLIBCXX_3.4
    0000000000002004 r _ZStL19piecewise_construct
    0000000000004151 b _ZStL8__ioinit
                     U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@@GLIBCXX_3.4
    00000000000021ac r __FRAME_END__
    0000000000002014 r __GNU_EH_FRAME_HDR
    0000000000004010 D __TMC_END__
    0000000000004010 B __bss_start
                     U __cxa_atexit@@GLIBC_2.2.5
                     w __cxa_finalize@@GLIBC_2.2.5
    0000000000004000 D __data_start
    0000000000001160 t __do_global_dtors_aux
    0000000000003d88 d __do_global_dtors_aux_fini_array_entry
    0000000000004008 D __dso_handle
    0000000000003d78 d __frame_dummy_init_array_entry
                     w __gmon_start__
    0000000000003d88 d __init_array_end
    0000000000003d78 d __init_array_start
    00000000000012d0 T __libc_csu_fini
    0000000000001260 T __libc_csu_init
                     U __libc_start_main@@GLIBC_2.2.5
    0000000000004010 D _edata
    0000000000004158 B _end
    00000000000012d8 T _fini
    0000000000001000 t _init
    00000000000010c0 T _start
    0000000000004150 b completed.8060
    0000000000004000 W data_start
    00000000000010f0 t deregister_tm_clones
    00000000000011a0 t frame_dummy
    00000000000011a9 T main
    0000000000001120 t register_tm_clones
    
    
    # 例子
    $ ldd main
            linux-vdso.so.1 (0x00007fff2c7d6000)
            libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fd49d627000)
            libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd49d435000)
            libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fd49d2e6000)
            /lib64/ld-linux-x86-64.so.2 (0x00007fd49d81b000)
            libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fd49d2cb000)
    

    Further reading

    The definitive guide to GCC is the official reference manual, “Using GCC”, published by GNU Press:

    相关文章

      网友评论

          本文标题:《an introduction to gcc》阅读笔记

          本文链接:https://www.haomeiwen.com/subject/aphfbltx.html