victory的博客

长安一片月,万户捣衣声

0%

gcc | 编译和链接

编译和链接

  • 通过一个代码示例理解编译与链接的过程

    1. 安装gcc

      1
      sudo apt-get install build-essential
    2. 编写示例代码

      main.c

      1
      2
      3
      4
      5
      6
      7
      8
      9
      #include<stdio.h>

      int add(int a, int b);

      int main(){
      printf("hello,world!\n");
      int result = add(5,5);
      return 0;
      }

      math.c

      1
      2
      3
      int add(int a, int b){
      return a + b;
      }
    3. 编译示例代码的两个文件main.c和math.c,得到对应的目标文件(Object File)main.o和math.o

      注:目标文件是二进制文件,文件格式是ELF(Executable and Linkable Format),ELF格式是linux下所有可执行文件的通用格式。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      gcc -c main.c
      gcc -c math.c

      file main.o
      #main.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), #not stripped

      readelf -h main.o
      ELF Header:
      Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
      Class: ELF64
      Data: 2's complement, little endian
      Version: 1 (current)
      OS/ABI: UNIX - System V
      ABI Version: 0
      Type: REL (Relocatable file)
      Machine: Advanced Micro Devices X86-64
      Version: 0x1
      Entry point address: 0x0
      Start of program headers: 0 (bytes into file)
      Start of section headers: 672 (bytes into file)
      Flags: 0x0
      Size of this header: 64 (bytes)
      Size of program headers: 0 (bytes)
      Number of program headers: 0
      Size of section headers: 64 (bytes)
      Number of section headers: 14
      Section header string table index: 13
      1
      2
      3
      readelf -S main.o
      # .text 代码区域
      # .data 数据区域

      objdump -s -d main.o

      -d:将代码段反汇编

      -s:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出- g,即需要调试信息。

      右侧汇编指令中有两个call指令,既主函数中对printf和add的调用,从机器码可以看出跳转地址为0,需要在后续根据重定位表更新到printf和add的实际地址。

      objdump -r main.o

      查看两个函数调用的信息(地址偏移量、类型和值)

    4. 链接

      链接调用的函数机器码并组装为可执行文件main

    1
    gcc main.o math.o -o main
    1. 执行可执行文件main
    1
    2
    ./main
    # 输出hello,world
  • 通过makefile来进行编译链接步骤

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    all: main

    main: main.o math.o
    gcc main.o math.o -o main

    main.o: main.c
    gcc -c main.c

    math.o: math.c
    gcc -c math.c

    clean:
    rm main main.o math.o
    1
    make main