The story behind GCC & address allocation of C program constant variables

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;./testRun 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

  1. addr21line
    Help the debugger locate the corresponding source code during debugging.
  2. ar
    Used to create static link libraries.
  3. ld
    for linking.
  4. as
    for assembly.
  5. ldd
    Check the link library used by the executable file.
  6. size
    View the size of each section in the executable file.
  7. readelf
    View the contents of each section of ELF.
  8. 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)

img

#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.