The story behind the GCC compiler

1. Use gcc to generate .a static library and .so dynamic library

Static library : It will be linked to the target code when the program is compiled, and the static library will no longer be needed when the program is running.

Dynamic library : The library is not linked to the target code when the program is compiled, but is loaded only when the program is running, so the dynamic library needs to be in the program when the program is running.

  1. Create a test1 folder, and create three subprograms hello.h, hello.c and main.c in the folder

    mkdir test1	# 创建test1文件夹
    cd test1 # 进入该文件
    vim hello.h	# 编辑hello.h
    vim hello.c	# 编辑hello.c
    vim main.c	# 编辑main.c
    

    The content of the program hello.h is as follows:

    #ifndef HELLO_H 
    #define HELLO_H 
    void hello(const char *name); 
    #endif //HELLO_H
    

    The content of the program hello.c is as follows:

    #include <stdio.h> 
    #include "hello.h"
    void hello(const char *name) 
    {
          
          
    	printf("Hello %s!\n", name);
    }
    

    The content of program main.c is as follows:

    #include "hello.h" 
    int main() 
    {
          
          
    	hello("everyone"); 
    	return 0; 
    }
    
  2. Compile hello.c into .o file

    Both static libraries and dynamic libraries are created by .o files, so they need to be compiled into .o files first

    gcc -c hello.c	# 编译成 .o文件
    ls # 查看
    
  3. Create a static library from the .o file and use it in the program

    a. .o file to create a static library

    The naming convention of the static library file name is lib as the prefix, followed by the static library name, the extension is .a. Such as: libmyhello.a

    ar -crv libmyhello.a hello.o # 生成静态库
    ls # 查看
    

    b. Use static libraries in the program

    # 方法一
    gcc -o hello main.c -L. -lmyhello
    # 方法二
    gcc main.c libmyhello.a -o hello
    # 方法二
    gcc -o main.c	# 先生成 main.o
    gcc -o hello main.o libmyhello.a
    

    -L .: Indicates that the library to be connected is in the current directory

    Then ./hello , execute the program:

    we can try to delete the libmyhello static library and execute the hello program again (see whether the static library is needed when the program is running)

    rm libmyhello.a	# 删除libmyhello.a
    ./hello	# 运行hello程序
    

    Result: The static library will be linked to the target code when the program is compiled, and the static library will no longer be needed when the program is running.

  4. Create a dynamic library from the .o file and use it in the program

    a. .o file to create a dynamic library

    The naming convention of dynamic library file name is lib as the prefix, followed by the static library name, the extension is .so. Such as: libmyhello.so

    gcc -shared -fPIC -o libmyhello.so hello.o	# 生成动态库
    ls	# 查看
    

    -shared : This option specifies to generate a dynamic link library

    -fPIC : means to compile to position independent code

    b. Use dynamic libraries in programs

    # 方法一
    gcc -o hello main.c -L. -lmyhello
    # 方法二
    gcc main.c libmyhello.so -o hello
    

    But an error will be reported when running the hello program (the library file cannot be found in /usr/lib)

    Reason: When the program is running, it will find the required dynamic library files in directories such as /usr/lib and /lib. If found, load the dynamic library, otherwise it will prompt similar errors and terminate the program.

    At this point, we generate the following libmyhello.a static library again to determine which library file will be used by the gcc command when the static library and the dynamic library have the same name:

    ar -crv libmyhello.a hello.o # 生成静态库
    gcc -o hello main.c -L. -lmyhello
    ./hello
    

    An error will also be reported. It can be seen that when the static library and the dynamic library have the same name, the gcc command will give priority to the dynamic library, and by default it will connect to the dynamic libraries in directories such as /usr/lib and /lib

    Solution: Move the file libmyhello.so to the directory /usr/lib

    sudo mv libmyhello.so /usr/lib
    ./hello
    

2. Comparison of executable file size generated by dynamic library and static library

  1. Create a test2 folder, and create subprograms sub1.h, sub1.c, sub2.h, sub2.c, main.c in the folder respectively

    mkdir test2
    cd test2
    vim sub1.h
    vim sub1.c
    vim sub2.h
    vim sub2.c
    vim main.c
    

    The contents of sub1.h are as follows:

    #ifndef SUB1_H
    #define SUB1_H 
    float x2x(int a, int b);
    #endif //SUB1_H
    

    The contents of sub1.c are as follows:

    #include"sub1.h"
    
    float x2x(int a, int b){
          
          
    	return a + b;	//相加
    }
    

    The contents of sub2.h are as follows:

    #ifndef SUB2_H
    #define SUB2_H 
    float x2y(int a, int b);
    #endif //SUB2_H
    

    The content of sub2.c is as follows:

    #include"sub2.h"
    
    float x2y(int a, int b){
          
          
            return a * b;	//相乘
    }
    

    The contents of main.c are as follows:

    #include<stdio.h>
    #include"sub1.h"
    #include"sub2.h"
    
    int main(){
          
          
    	int a = 2, b = 3;
    	printf("%d + %d = %f\n", a, b, x2x(a, b));
    	printf("%d × %d = %f\n", a, b, x2y(a, b));
    	return 0;
    }
    
  2. Link with static library files to generate executable files

    a. Compile sub1.c and sub2.c into .o files

    gcc -c sub1.c sub2.c
    ls
    

    b. .o file to create a static library

    ar -crv libsub1.a sub1.o
    ar -crv libsub2.a sub2.o
    ls
    

    c. Use static libraries in the program

    gcc main.c libsub1.a libsub2.a -o main1
    ./main1
    
  3. Link with dynamic library files to generate executable files

    a. .o file to create a dynamic library

    gcc -shared -fPIC -o libsub1.so sub1.o
    gcc -shared -fPIC -o libsub2.so sub2.o
    ls
    

    b. Use dynamic libraries in programs

    gcc main.c libsub1.so libsub2.so -o main2
    # 将文件 libsub1.so、libsub2.so 移动到目录/usr/lib 中
    sudo mv libsub1.so /usr/lib
    sudo mv libsub2.so /usr/lib
    ./main2
    

    d. Comparison of the size of two executable files

    According to the above method, the executable file generated by static library linking is not completely generated by static library linking. Because stdio.h called in main.c is dynamically linked, it needs to be re-linked from static library to generate an executable File, otherwise it may appear that the executable file generated by the static library is smaller than the one generated by the dynamic library

    gcc -static main.c libsub1.a libsub2.a -o main1	# 重新由静态库生成
    size main1
    ldd main1
    size main2
    ldd main2
    

    size: used to view file size

    ldd: Check which dynamic libraries are linked

Third, how does the gcc compiler compile

  1. Create a test0 folder and create a hello.c program in the folder

    mkdir test0
    cd test0
    vim hello.c
    

    The content of hello.c is as follows:

    #include <stdio.h>
    int main(void)
    {
          
          
    	printf("Hello World! \n");
    	return 0;
    }
    
  2. The compilation process of the program

    a. Pre-compilation (preprocess the source file hello.c file to generate hello.i)

    gcc -E hello.c -o hello.i
    

    b. Compile (compile the hello.i file generated by preprocessing to generate the assembler hello.s)

    gcc -S hello.i -o hello.s
    

    c. Assembly (Assemble the generated hello.s file to generate the object file hello.o)

    # 用gcc进行汇编
    gcc -c hello.s -o hello.o
    # 用as进行汇编
    as -c hello.s -o hello.o
    

    d. Link (divided into static link and dynamic link to generate executable files)

    # 动态链接
    gcc hello.c -o hello
    # 静态链接
    gcc -static hello.c -o hello
    

    e. Use size to view the file size, ldd links those dynamic libraries

  3. Analysis of ELF files

    a. A typical ELF file contains the following sections

    (1) .text: Instruction code segment of the compiled program

    (2) .rodata: ro stands for read only, that is, read-only data (such as constant const)

    (3) .data: initialized C program global variables and static local variables

    (4) .bss: Uninitialized C program global variables and static local variables

    (5) .debug: debugging symbol table, the debugger uses the information in this section to help debugging

    readelf -S hello  # 查看各个section(段)的信息
    

    b. Disassemble ELF

    objdump -S disassembles it and displays the mixed C language source code:

    gcc -o hello -g hello.c
    objdump -S hello
    

    Or directly use objdump -D hello to disassemble (there will be no C language source code)

  4. Download and install nasm in ubuntu, compile the sample assembly code "hello.asm" to generate an executable program, and compare it with the size of the executable program generated by the above C code compilation

    a. Install nasm compiler

    Download the NSAM software package: https://www.nasm.us/pub/nasm/releasebuilds/2.14rc16/nasm-2.14rc16.tar.gz

    Enter the download folder and unzip the file:

    cd 下载
    tar zxvf nasm-2.14rc16.tar.gz
    

    installation:

    cd nasm-2.14rc16/
    ./configure
    make
    sudo make install
    

    Check whether the installation is successful:

    nasm -version
    

    b. Compile and assemble the hello.asm file and compare the size of the program generated by the compilation of C code

    The content of hello.asm is as follows:

    ; hello.asm 
    section .data            ; 数据段声明
            msg db "Hello, world!", 0xA     ; 要输出的字符串
            len equ $ - msg                 ; 字串长度
    section .text            ; 代码段声明
    global _start            ; 指定入口函数
    _start:                  ; 在屏幕上显示一个字符串
            mov edx, len     ; 参数三:字符串长度
            mov ecx, msg     ; 参数二:要显示的字符串
            mov ebx, 1       ; 参数一:文件描述符(stdout) 
            mov eax, 4       ; 系统调用号(sys_write) 
            int 0x80         ; 调用内核功能
                             ; 退出程序
            mov ebx, 0       ; 参数一:退出代码
            mov eax, 1       ; 系统调用号(sys_exit) 
            int 0x80         ; 调用内核功能
    
    

    Compile (elf defaults to 32 bits):

    nasm -f elf64 hello.asm
    

    link:

     ld -s -o hello hello.o
    

    c. Comparing the size of executable program generated by compilation and C code

    It can be seen that the executable program generated directly by assembly compilation is much smaller than the executable program generated directly by C code compilation

Fourth, understand how the actual program completes code design with the help of third-party library functions

  1. As a tourist, experience the ancient BBS that is about to disappear (a terminal program controlled by keyboard cursor)

    a.In win10 system, "Control Panel" -> "Programs" -> "Enable or Close Windows Functions" , enable "telnet client" and "Windows Subsystem for Linux" (will be used later), and restart.

    b. Open a cmd command line window and enter the following command:

     telnet bbs.newsmth.net
    

    As a tourist, experience the ancient BBS that is about to disappear (a terminal program controlled by keyboard cursor)

  2. Implementation of Snake-eating Game by Compiling C Language in Linux Environment

    a. Understand the most commonly used cursor library (curses) for terminal programs in Linux systems

    • initscr() : initscr() is a function that must be called by general curses programs first. Once this function is called, the system will start the curses mode according to the form of the terminal
    • endwin() : curses usually ends the program by calling endwin(). endwin() can be used to turn off curses mode, or temporarily leave curses mode
    • refresh() : refresh() is the most frequently called function of curses
    • move(y,x) : move the cursor to the position of x,y
    • echochar(ch)/addch(ch) : display a character

    For more detailed functions of library functions, please refer to: Linux curses library

    b. Ubuntu18.04 install curses library

    sudo apt-get install libncurses5-dev
    

    Which directories can the header files and library files be installed through the whereis command:

    c.C language compilation in the Linux environment to realize the snake game

    mkdir testSnake # 新建一个文件夹
    cd testSnake # 进入该文件
    vim mysnake.c
    gcc mysnake.c -lcurses -o mysnake # 编译链接生成可执行文件
    ./mysnake
    
    

    For the content of mysnake.c, please refer to: C language compilation in Linux environment to achieve snake game

    There will be a warning when compiling (you can leave it alone)

    -lcurses: link curses library

    ./mysnake runs the program, the effect is as follows:

Five, summary

Through this experiment, learn how to use gcc to generate static libraries (*.a) and dynamic libraries (*.so), and use static/dynamic library linking to generate executable files; at the same time, the compilation process of a program is divided into "precompilation—> Compile -> Assemble -> Link" four processes.

6. Reference link

Guess you like

Origin blog.csdn.net/xwmrqqq/article/details/109071198