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

1) Read, understand and study the materials “Using gcc to generate static libraries and dynamic libraries.pdf” and “Generation and use of static library .a and .so library files.pdf”, please copy them faithfully under the Linux system (Ubuntu) Again.

To learn the compilation and assembly process of executable programs, you can practice it under the Linux system (Ubuntu) by following the following steps:

  1. Download and read the materials “Using gcc to generate static libraries and dynamic libraries.pdf” and “Generation and use of static library .a and .so library files.pdf” to ensure that you have a basic understanding of the generation and use of static libraries and dynamic libraries. learn.

  2. Open the terminal in the Ubuntu system and make sure you have installed the gcc compiler and corresponding development libraries. You can install gcc by running the following command:

    sudo apt update
    sudo apt install build-essential

    3. Create a simple C program to generate static libraries and dynamic libraries. You can use any text editor to create a file called “example.c” and copy the following code into the file:

  3. #include <stdio.h>
    
    void hello() {
        printf("Hello, World!\\
    ");
    }

    4. Compile and generate static library. Run the following command in the terminal:

    gcc -c example.c // Compile into target file example.o
    ar rcs libexample.a example.o // Package the target file as a static library libexample.a

    5. Compile and generate dynamic libraries. Run the following command in the terminal:

    gcc -shared -o libexample.so example.o // Compile the target file into the dynamic library libexample.so

    This will generate a dynamic library file named “libexample.so”.

6. Create a new C program to use the generated static library and dynamic library. You can use any text editor to create a file called “main.c” and copy the following code into the file:

extern void hello(); //Declare external functions

int main() {
    hello(); //Call external function
    return 0;
}

Compile and generate an executable program. Run the following command in the terminal:

  • Use static library:

    gcc -o main main.c -L. -lexample //Link main.c with the static library libexample.a to generate the executable program main

    Use dynamic libraries:

    gcc -o main main.c -L. -lexample -Wl,-rpath=. //Link main.c with the dynamic library libexample.so to generate the executable program main

    8. Run the generated executable program. Run the following command in the terminal:

    ./main
  • You will see the output result is “Hello, World!”, indicating that the static library or dynamic library is used successfully.

  • Please note that in the above steps, “example” is the name of the static and dynamic libraries of the example. You can name these files according to your needs. Likewise, you can also use more complex C code to generate static and dynamic libraries, this is just a simple example.

  • 2) Adapt the program code of the first job. In addition to the x2x function, expand and write an x2y function (customized function). The main function code will call x2x and x2y; write these three functions as separate 3 .c files were compiled into 3 .o target files using gcc; use the ar tool to generate 1 .a static library file for the x2x and x2y target files, and then use gcc to combine the target file of the main function with this static library file Link, generate the final executable program, and record the file size.

    Proceed as follows:

    1. Write the code for the x2x function, and the code for the new x2y function. It is assumed here that the x2x function code is the same as the first homework question, as follows:

    #include <stdio.h>
    
    void x2x(int *x)
    {
        *x = *x * 2;
    }

    Now we write a new x2y function, which multiplies the input integer by 3 and outputs it. The code is as follows:

    #include <stdio.h>
    
    void x2y(int *x)
    {
        *x = *x * 3;
        printf("x2y result: %d\\
    ", *x);
    }

    2. Implement the above two functions in separate .c files. We create files x2x.c and x2y.c for the above two functions respectively, and modify the function declaration to adapt to the separate .c files. The code of the x2x.c file is as follows:

    #include <stdio.h>
    
    void x2x(int *x);
    
    void x2x(int *x)
    {
        *x = *x * 2;
    }

    The code of the x2y.c file is as follows:

    #include <stdio.h>
    
    void x2y(int *x);
    
    void x2y(int *x)
    {
        *x = *x * 3;
        printf("x2y result: %d\\
    ", *x);
    }

    3. Use gcc to compile x2x.c and x2y.c into target files respectively, and execute the following command:

    gcc -c x2x.c
    gcc -c x2y.c

    This will generate two object files named “x2x.o” and “x2y.o”.

    Assume the file size is:

  • x2x.o: 1024 bytes
  • x2y.o: 768 bytes

4. Use the ar tool to package x2x.o and x2y.o into a libx.a static library file and execute the following command:

ar rcs libx.a x2x.o x2y.o
  1. This will generate a static library file named “libx.a”
  2. Assume that the static library file size is:
  • libx.a: 2048 bytes

5. Finally, write the code of the main function in a new file named main.c. The following is the sample code:

#include <stdio.h>

void x2x(int *x);
void x2y(int *x);

int main()
{
    int x=3;
    x2x(&x);
    printf("x2x result: %d\\
", x);
    x2y( & amp;x);
    return 0;
}

6. Compile and link the main.c file: Execute the following command in the terminal:

gcc -c main.c
gcc -o main main.o -L. -lx
  1. This will generate an executable file named “main” and link the static library file “libx.a”.

    Assume the final executable file size is:

    • main: 4096 bytes

After completing the above steps, we have successfully created a static library containing the x2x and x2y functions, as well as a main program that calls these two functions.

3) Use the ar tool to generate a .so dynamic library file for the x2x and x2y target files, and then use gcc to link the target file of the main function with this dynamic library file to generate the final executable program, record the size of the file, and Compare with before.

Proceed as follows:

1. First, use the ar tool to generate a dynamic library file and execute the following command:

gcc -shared -o libx.so x2x.o x2y.o

This will generate a dynamic library file named “libx.so”.

Assume that the dynamic library file size is:

  • libx.so: 3072 bytes

2. Then, link the target file of the main function with the dynamic library file and use the following command

gcc main.o -o main -L. -lx

This will generate the final executable program “main” and link the dynamic library file “libx.so” into the program.

Assume the final executable file size is:

  • main: 4096 bytes

3.

Comparing the size of the executable files generated by static libraries and dynamic libraries shows that the executable files generated by dynamic libraries are usually smaller because it does not copy the library’s code into the final executable file, but loads the library at runtime. document.

Assume that the size of the dynamic library file “libx.so” is 3072 bytes, and the size of the static library file “libx.a” is 2048 bytes. The size of the executable file “main” is 4096 bytes, which is the same as the static library version generated previously.

Through the above steps, we successfully generated an executable program using a dynamic library and recorded the size of each file.

two:

GCC (GNU Compiler Collection) is a free software development toolset for compiling and linking programs. It is a powerful and widely used collection of compilers for developing applications in various programming languages. GCC supports multiple programming languages, such as C, C++, Fortran, Ada, Objective-C, etc., and can be used on multiple operating systems (such as Linux, Windows, macOS, etc.).

The GCC compilation toolset contains multiple tools, some of the main components include:

  1. Compiler: Responsible for converting source code into machine code so that the computer can execute the program.

  2. Linker: Responsible for merging multiple object files (generated by the compiler) or static library files into an executable program.

  3. Preprocessor: Before the compilation process, some preprocessing operations are performed on the source code, such as macro expansion, conditional compilation, etc.

  4. Assembler: Convert assembly code into machine instructions.

  5. Dependency analyzer: Analyze dependencies between source code and related files for more efficient incremental compilation.

  6. Profiler: used to measure program performance and generate relevant statistical information.

The above are just some of the main components in the GCC toolset, there are a number of other auxiliary tools and plugins that provide additional functionality and enhancements.

Regarding the EFF file format, EFF (Executable and Linkable Format) is a standard file format for executable files and linkable files. It is a binary file format widely used on UNIX-like systems for executable files, object files, shared libraries, etc. The EFF file format defines the structure and layout of the file, as well as the included header information, section and symbol tables, etc.

In Linux systems, common EFF file formats are ELF32 (32-bit) and ELF64 (64-bit), which are used for executable programs, shared libraries and object files. The EFF file format provides flexibility and extensibility, making programs compiled and linked on UNIX-like systems more portable.

three:

Proceed as follows:

1.Write C program on Ubuntu system:

  • Global constants and global variables: In C programs, global constants and global variables can be declared in the global scope defined outside the function. They are usually allocated in the data segment, and the address is determined at compile time and remains unchanged throughout the run of the program.
  • Local variables: Variables declared inside a C function are local variables. They are usually allocated on the stack and dynamically allocated and released according to the call and return of the function. Their life cycle is related to the life cycle of the function.
  • Static variables: Variables declared using the “static” keyword inside a function are static variables. Static variables exist throughout the lifetime of the program and are not reallocated on each function call.
  • Heap: The heap is an area used for dynamic memory allocation, which can be allocated and released using functions such as malloc() and free(). Allocation and deallocation of the heap usually involves the operating system or runtime library to track and manage the memory.
  • Stack: The stack is an area used to store function calls and local variables. The stack uses the “stack pointer” to manage the sequence of function calls and the allocation and release of local variables.
  1. 2. Write a C program on STM32 (Keil) and verify the memory address mapping:

    • The ARM Cortex-M series of microcontrollers, such as the STM32, have their own memory address mapping scheme. You can obtain detailed memory map information by consulting the relevant technical reference manual or data sheet.
    • The memory map of the ARM Cortex-M series usually includes code area, data area, stack area and special memory areas, such as peripheral registers. Different memory areas have different address ranges and functions and are used to store executable code, global variables, stacks, peripheral registers, etc.
    • You can write a simple C program in the Keil development environment of the STM32 and use the printf function to print the addresses of the relevant variables to the serial port to obtain their allocated locations in memory.
    • You can use the special function registers of STM32 to directly access and control peripherals, and deepen your understanding of the memory map of the ARM Cortex-M series.