Article Directory
-
-
- 1. Use gcc to generate .a static library and .so dynamic library
- 2. Comparison of executable file size generated by dynamic library and static library
- Third, how does the gcc compiler compile
- Fourth, understand how the actual program completes code design with the help of third-party library functions
- Five, summary
- 6. Reference link
-
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.
-
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; }
-
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 # 查看
-
Create a static library from the .o file and use it in the program
a.
.o file to create a static libraryThe 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.
-
Create a dynamic library from the .o file and use it in the program
a.
.o file to create a dynamic libraryThe 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
-
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; }
-
Link with static library files to generate executable files
a.
Compile sub1.c and sub2.c into .o filesgcc -c sub1.c sub2.c ls
b.
.o file to create a static libraryar -crv libsub1.a sub1.o ar -crv libsub2.a sub2.o ls
c.
Use static libraries in the programgcc main.c libsub1.a libsub2.a -o main1 ./main1
-
Link with dynamic library files to generate executable files
a.
.o file to create a dynamic librarygcc -shared -fPIC -o libsub1.so sub1.o gcc -shared -fPIC -o libsub2.so sub2.o ls
b.
Use dynamic libraries in programsgcc 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 filesAccording 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
-
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; }
-
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 -
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 ELFobjdump -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)
-
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 compilerDownload 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 codeThe 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 codeIt 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
-
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)
-
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 librarysudo 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 gamemkdir 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
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.