Table of Contents
1. Use gcc to generate static libraries and dynamic libraries
Example 1
1.Create a directory
2.gcc compiles and obtains the .o file
3. Create a static library
4. Use static libraries
5. Verify the usage characteristics of static libraries
6. Create a dynamic library
7. Use dynamic libraries
8. Comparison of static libraries and dynamic libraries
Example 2
1.Create file
2. Generation and use of static library .a files
3. Use of dynamic libraries
Example Three (First Assignment Adaptation)
1.Create file
2. Create static library files
3. Create dynamic library files
4. Comparison of generated files between static libraries and dynamic libraries
2. GCC is not fighting alone.
3. Write a C program, review concepts such as global constants, global variables, local variables, static variables, heaps, and stacks, and program and verify them in the Ubuntu (x86) system and STM32 (Keil) (STM32 printf information through the serial port to the host computer serial port assistant). 1) Summarize the allocation addresses of heap, stack, global, local and other variables in C programs under Ubuntu and stm32, and conduct comparative analysis; 2) Deepen the understanding of the memory address mapping of ARM Cortex-M/stm32F10x. The picture below is a schematic diagram of the memory address mapping of Cortex-M4 (basically the same as Cortex-M3/stm32F10x, with only minor differences)
Summarize
1. Use gcc to generate static libraries and dynamic libraries
Example 1
1.Create directory
Command description
#mkdir test /Create a new directory #cd test /Open directory for editing #touch hello.h /Create a new file in this directory #vim hello.h /Open the file for editing #ls /Query all files in the file directory
hello.h
#ifndef HELLO_H #define HELLO_H void hello(const char *name); #endif
hello.c
#include<stdio.h>void hello(const char *name) {printf("hello %s\\ ",name);}
main.c
#include“hello.h”int main() {hello("everyone!");return 0;}
2.gcc compiles and obtains .o file
3. Create static library
Static library file naming convention: The prefix is lib, plus the static library name, and the extension is .a.
4. Use static library
Use internal functions in a static library: You need to include the prototype declarations of these public functions in the source program that uses these public functions, and then specify the static library name when using the gcc command to generate the target file. Gcc will extract the name from the static library. Connect these public functions into the object file.
①gcc -o hello main.c -L. -lmyhello
②gcc main.c libmyhello.a -o hello
③ First generate the main.o file gcc -c main.c
Generate the executable file gcc -o hello main.o libmyhello.a
5. Verify the usage characteristics of the static library
After deleting the static library and running the executable file, it is found that the program can still run normally, indicating that the static library has nothing to do with the executable program. At the same time, it is explained that the static library is connected to the target code when the program is compiled.
6. Create dynamic library
Dynamic library file naming convention: The prefix is lib, plus the dynamic library name, and the extension is .so.
7. Use dynamic library
An error occurred. Although the current directory is used when connecting, because when running the executable file, the library file is found in usr/lib
, so libmyhello.so
Copy it to the directory usr/lib
8. Comparison between static library and dynamic library
Compile with gcc and get the .o file
gcc -c hello.c
Create static library
ar -crv libmyhello.a hello.o
Create dynamic library
gcc -shared -fPIC -o libmyhello.so hello.o
Use libraries to generate executable files
gcc -o hello main.c -L. -lmyhello
Execute executable file
./hello
When executing the executable file, an error will be reported. It can be seen that when the static library and the dynamic library exist at the same time, the program will give priority to the dynamic library.
Example 2
1.Create file
A1.c
#include<stdio.h> void print1(int arg) { printf("A1 print arg:%d\\ ",arg); }
A2.c
#include<stdio.h> void print2(char *arg) { printf("A2 printf arg:%s\\ ",arg); }
A. h
#ifndef A_H #define A_H void print1(int); void print2(char *); #endif
test.c
#incldue<stdio.h> #include"A.h" int main() { print1(1); print2(test); return(0); }
2. Generation and use of static library .a files
Enter the following command under terminal control: gcc -c A1.c A2.c
to generate the target file; ar crv libfile.a A1.o A2.o
to generate the static library .a file; Use the .a file to create an executable file gcc -o test test.c libfile.a
;./test
Run the executable program
3. Use of dynamic libraries
gcc -shared -fPIC -o libfile.so A1.o A2.o
gcc -o test test.c libfile.so
Example Three (First Assignment Adaptation)
1. Create files
Create an .o file: Control the terminal and run the command gcc -c sub1.c sub2.c
sub1.c
float x2x(int a,int b) { float c=0; c=a + b; return 0; }
sub2.c
float x2y(int a,int b) { float c=0; c=a/b; return c; }
sub.h
#ifndef SUB_H #define SUB_H float x2x(int a,int b); float x2y(int a,int b); #endif
main.c
#include<stdio.h> #incldue"sub.h" void main() { int a,b; printf("Please input the value of a:"); scanf("%d", & amp;a); printf("Please input the value of b:"); scanf("%d", & amp;b); printf("a + b=%.2f\\ ",x2x(a,b)); printf("a/b=%.2f\\ ",x2y(a,b)); }
2. Create static library file
ar crv libsub.a sub1.0 sub2.o
Generate executable file gcc -o mian main.c libsub.a
3. Create dynamic library file
gcc shared -fPIC -o libsub.so sub1.o sub2.o
gcc -o main main.c libsub.so
4. Comparison of generated files of static libraries and dynamic libraries
static library
dynamic library
After comparison, it was found that the static library is much smaller than the dynamic library, and there is also a small difference in the size of the generated executable file between the two.
2. GCC is not fighting alone
Common gcc commands: code examples:
test.c
#include<stdio.h> int main(void) { printf("Hello World!\\ "); return 0; }
1.Compile
gcc test.c -o test
2. Actual compilation
①Pre-compilation
gcc -E test.c -o test.i
Part of the content of test.i:
②Compile into assembly code
gcc -S test.i -o test.s
Contents of test.s:
③Compilation
gcc -c test.s -o test.o
④Connection
gcc test.o -o test
3. Compilation of multiple program files
①gcc source file 1 source file 2 -o generated executable file
Example:
②gcc -c source file 1 -o generate .o file 1
gcc -c source file 1 -o generate .o file 2
gcc generates .o file 1 generates .o file 2 -o generated executable file
Example:
4. Error checking
gcc -pedantic test.c -o test1 -pedantic: Helps find some code that does not comply with the ANSI/ISO C standard. When non-compliant code appears, a warning message will be issued.
gcc -Wall test.c -o test2 -Wall: Helps find some code that does not comply with the ANSI/ISO C standard. When non-compliant code appears, gcc will issue as many warning messages as possible
gcc -Werror test.c -o test3 -Werror:gcc will stop compilation wherever warnings are generated, forcing code modifications
5. Library file connection
Library files: dynamic link library (.so), static link library (.a)
Function library: header file (.h), library file (.so)
Note: Header files are generally placed in the /usr/include directory, and library files are generally placed in the /usr/lib directory
①Compile
gcc -c -I /usr/include source file -o generate .o file
②Link
gcc -L /usr/lib dynamic link library file name generates .o file -o generates executable file
③Mandatory use of static link libraries
When gcc links, it will give priority to the dynamic link library. If you want to force the use of the static link library, add -static to the command.
gcc -L /usr/lib -static static link library file name to generate .o file -o to generate executable file
Search path order during static linking: a. ld will look for the parameter -L in the gcc command. b. gcc’s environment variable LBRARY_PATH (specifies the search path for program static link library files) c. Default directory/lib /usr/lib /usr/local/lib Search path order when dynamically linking: a. The dynamic library search path specified when compiling the target code b. Environment variable LD_LIBRARY_PATH (specifies the search path for program dynamic link library files) c. The dynamic library search path specified in the configuration file /etc/ld.so.conf d. Default dynamic library search path/lib e. Default dynamic library search path/usr/lib
gcc partners
Some tools
- addr21line
Help the debugger locate the corresponding source code during debugging. - ar
Used to create static link libraries. - ld
for linking. - as
for assembly. - ldd
Check the link library used by the executable file. - size
View the size of each section in the executable file. - readelf
View the contents of each section of ELF. - objdump
disassemble
3. Write a C program and review global constants , global variables, local variables, static variables, heap, stack and other concepts are programmed and verified in Ubuntu (x86) system and STM32 (Keil) respectively (STM32 printf information to the host computer serial port assistant through the serial port). 1) Summarize the allocation addresses of heap, stack, global, local and other variables in C programs under Ubuntu and stm32, and conduct comparative analysis; 2) Deepen the understanding of the memory address mapping of ARM Cortex-M/stm32F10x. The picture below is a schematic diagram of the memory address mapping of Cortex-M4 (basically the same as Cortex-M3/stm32F10x, with only minor differences)
#include <stdio.h> #include <stdlib.h> //Define global variables int init_global_a = 1; int uninit_global_a; static int inits_global_b = 2; static int uninits_global_b; void output(int a) { printf("hello"); printf("%d",a); printf("\\ "); } int main( ) { //Define local variables int a=2; static int inits_local_c=2, uninits_local_c; int init_local_d = 1; output(a); char *p; char str[10] = "lmy"; //Define constant string char *var1 = "1234567890"; char *var2 = "qwertyuiop"; //Dynamic allocation int *p1=malloc(4); int *p2=malloc(4); //freed free(p1); free(p2); printf("Stack area-variable address\\ "); printf(" a:%p\\ ", & amp;a); printf("init_local_d:%p\\ ", & amp;init_local_d); printf(" p:%p\\ ", & amp;p); printf(" str:%p\\ ", str); printf("\\ Heap area-dynamic application address\\ "); printf(" %p\\ ", p1); printf(" %p\\ ", p2); printf("\\ Global area - global variables and static variables\\ "); printf("\\ .bss section\\ "); printf("Global external no initial value uninit_global_a: %p\\ ", & amp;uninit_global_a); printf("static external no initial value uninits_global_b: %p\\ ", & amp;uninits_global_b); printf("static internal no initial value uninits_local_c: %p\\ ", & amp;uninits_local_c); printf("\\ .data section\\ "); printf("There is an initial value outside the global init_global_a: %p\\ ", & amp;init_global_a); printf("static external initial value inits_global_b: %p\\ ", & amp;inits_global_b); printf("Static internal initial value inits_local_c: %p\\ ", & amp;inits_local_c); printf("\\ Literal constant area\\ "); printf("Literal constant address: %p\\ ",var1); printf("Literal constant address: %p\\ ",var2); printf("\\ code area\\ "); printf("Program area address: %p\\ ", & amp;main); printf("Function address: %p\\ ", & amp;output); return 0; }
Compile:
gedit text.c gcc text.c -o text ./text
It can be found that Ubuntu’s address values in the stack area and heap area grow from top to bottom.
Variable allocation in STM32 (Keil) environment
#include "stm32f10x.h" // Device header #include <stdio.h> #include <stdlib.h> #include "Delay.h" #include "OLED.h" int globalVariable1; // global variable 1 int globalVariable2; // global variable 2 int main(void) { OLED_Init();//OLED initialization while(1) { int stackVariable1; // stack variable 1 int stackVariable2; // stack variable 2 int *heapVariable1 = malloc(sizeof(int)); // Heap variable 1 int *heapVariable2 = malloc(sizeof(int)); // Heap variable 2 static int staticVariable1; // Static global variable 1 static int staticVariable2; // Static global variable 2 static int staticLocalVariable1; // static local variable 1 static int staticLocalVariable2; // static local variable 2 OLED_ShowHexNum(1,1,(int) & &globalVariable1,8); OLED_ShowHexNum(2,1,(int) & & globalVariable2,8); OLED_ShowHexNum(3,1,(int) & amp;stackVariable1,8); OLED_ShowHexNum(4,1,(int) & amp;stackVariable2,8); //OLED_ShowHexNum(1,1,(int)heapVariable1,8); //OLED_ShowHexNum(2,1,(int)heapVariable2,8); //OLED_ShowHexNum(3,1,(int) & amp;staticVariable1,8); //OLED_ShowHexNum(1,1,(int) & amp;staticLocalVariable1,8); //OLED_ShowHexNum(2,1,(int) & amp;staticLocalVariable2,8); free(heapVariable1); // Release heap variable 1 free(heapVariable2); // Release heap variable 2 return 0; } }
Under STM32, the address storage in the stack area grows downward, but the address storage in the heap area grows upward.
STM32 is a family of microcontrollers based on ARM Cortex-M processors. These processors generally use a downward stack structure, also known as a stack that grows from high addresses to low addresses.
In the reverse stack structure, the initial value of the stack pointer points to the highest address on the top of the stack. As data on the stack is pushed onto the stack, the stack pointer decreases toward the lower address. When data is popped from the stack, the stack pointer is incremented toward higher addresses. The advantage of this stack structure is that it can easily detect stack overflow, because a stack overflow will cause the stack pointer to exceed the lowest address range of the stack.
Summary
Through several sample programs and related materials, I learned to use gcc to generate static libraries and dynamic libraries, as well as the generation and use of static library .a and .so library files. This experiment made me more proficient in using the gcc compilation tool and gained a better understanding of gcc. I believe that you will be more relaxed and content in the future learning process.