编译原理-链接实例分析

Posted Eliot_shao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编译原理-链接实例分析相关的知识,希望对你有一定的参考价值。

gcc-arm-none-eabi 工具链功能

1.arm-none-eabi-gcc :c语言编译器,可以将.c文件编译为.o的执行文件

2.arm-none-eabi-g++ :c++编译器,可以将.cpp文件编译成.o的执行文件

3.arm-none-eabi-ld : 链接器,链接所有的.o文件生成可执行文件

4.arm-none-eabi-objcopy :将链接器生成的文件转换为bin/hex等可烧写的格式

5.arm-none-eabi-gdb :调试器,将gdb连接到硬件产生的网络端口就可以实现硬件和代码的调试。

https://sourceware.org/binutils/docs/binutils/objcopy.html

objcopy can be used to generate a raw binary file by using an output target of ‘binary’ (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the load address of the lowest section copied into the output file.

https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html

Every section has a virtual address (VMA) and a load address (LMA);

The load address is specified by the AT or AT> keywords. Specifying a load address is optional.

If neither AT nor AT> is specified for an allocatable section, the linker will use the following heuristic to determine the load address:

  • If the section has a specific VMA address, then this is used as the LMA address as well.

  • If the section is not allocatable then its LMA is set to its VMA.

  • Otherwise if a memory region can be found that is compatible with the current section, and this region contains at least one section, then the LMA is set so the difference between the VMA and LMA is the same as the difference between the VMA and LMA of the last section in the located region.

  • If no memory regions have been declared then a default region that covers the entire address space is used in the previous step.

  • If no suitable region could be found, or there was no previous section then the LMA is set equal to the VMA.

This feature is designed to make it easy to build a ROM image. For example, the following linker script creates three output sections: one called ‘.text’, which starts at 0x1000, one called ‘.mdata’, which is loaded at the end of the ‘.text’ section even though its VMA is 0x2000, and one called ‘.bss’ to hold uninitialized data at address 0x3000. The symbol _data is defined with the value 0x2000, which shows that the location counter holds the VMA value, not the LMA value.

SECTIONS .text 0x1000 : *(.text) _etext = . ; .mdata 0x2000 : AT ( ADDR (.text) + SIZEOF (.text) ) _data = . ; *(.data); _edata = . ; .bss 0x3000 : _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;

The run-time initialization code for use with a program generated with this linker script would include something like the following, to copy the initialized data from the ROM image to its runtime address. Notice how this code takes advantage of the symbols defined by the linker script.

extern char _etext, _data, _edata, _bstart, _bend;char *src = &_etext;char *dst = &_data;/* ROM has data at end of text; copy it. */while (dst < &_edata) *dst++ = *src++;/* Zero bss. */for (dst = &_bstart; dst< &_bend; dst++) *dst = 0;

案例:

编码

main.c

int i = 10 ;
int f ;

int main(void)
        
        int k = 0 ; int m = 10; 
        
        k = m+i+f;
        
        return k ;
        

编译

$System/Tools/GNUArmToolchain/windows/bin/arm-none-eabi-gcc.exe -c main.c

生成main.o ,查看main.o的sections状态:

$System/Tools/GNUArmToolchain/windows/bin/arm-none-eabi-readelf.exe -S main.o

重点关注text.data.bass段的大小。

There are 10 section headers, starting at offset 0x260:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000058 00  AX  0   0  4  [ 2] .rel.text         REL             00000000 0001fc 000018 08   I  7   1  4  [ 3] .data             PROGBITS        00000000 00008c 000004 00  WA  0   0  4  [ 4] .bss              NOBITS          00000000 000090 000004 00  WA  0   0  4
  [ 5] .comment          PROGBITS        00000000 000090 00004a 01  MS  0   0  1
  [ 6] .ARM.attributes   ARM_ATTRIBUTES  00000000 0000da 00002a 00      0   0  1
  [ 7] .symtab           SYMTAB          00000000 000104 0000e0 10      8  11  4
  [ 8] .strtab           STRTAB          00000000 0001e4 000017 00      0   0  1
  [ 9] .shstrtab         STRTAB          00000000 000214 000049 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

链接生成elf

写一个链接脚本linktest.ld

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(main)
MEMORY

    IRAM1_CODE (r) : ORIGIN = 0x410000,  LENGTH = 0xEFFFF        
    TCM   (rw) : ORIGIN = 0x40,   LENGTH = 0x1ffc0


SECTIONS

    /*vector start_1 VMA在TCM,LMA在IRAM1_CODE*/
    .start_1 : 
        *(.text*)
     > TCM AT >IRAM1_CODE

    .start_2 : ALIGN(32) 
        __bss_start__ = . ;
        *(.bss .bss.*)
        __bss_end__ = . ;
     > IRAM1_CODE 
        
        .start_3 : ALIGN(32) 
        *(.data .data.*)
     > IRAM1_CODE 
        _exit = . ;

$System/Tools/GNUArmToolchain/windows/bin/arm-none-eabi-gcc.exe -o main.elf main.o -T ../linktest.ld

链接生成elf文件。

$System/Tools/GNUArmToolchain/windows/bin/arm-none-eabi-readelf.exe -S main.elf

There are 19 section headers, starting at offset 0x21c5c:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .start_1          PROGBITS        00000040 010040 000688 00  AX  0   0  4
  [ 2] .init             PROGBITS        000006c8 0106c8 000018 00  AX  0   0  4
  [ 3] .fini             PROGBITS        000006e0 0106e0 000018 00  AX  0   0  4
  [ 4] .rodata           PROGBITS        000006f8 0106f8 000048 00   A  0   0  4
  [ 5] .eh_frame         PROGBITS        00000740 010740 000004 00   A  0   0  4
  [ 6] .ARM.exidx        ARM_EXIDX       00000744 010744 000008 00  AL  1   0  4
  [ 7] .rodata._glo[...] PROGBITS        0000074c 01074c 000004 00   A  0   0  4
  [ 8] .start_2          NOBITS          00410720 020720 000041 00  WA  0   0 32  
  [ 9] .start_3          PROGBITS        00410780 020780 00043c 00  WA  0   0 32
  [10] .init_array       INIT_ARRAY      00410bbc 020bbc 000004 04  WA  0   0  4
  [11] .fini_array       FINI_ARRAY      00410bc0 020bc0 000004 04  WA  0   0  4
  [12] .init_array.00000 INIT_ARRAY      00410bc4 020bc4 000004 04  WA  0   0  4
  [13] .ARM.attributes   ARM_ATTRIBUTES  00000000 020bc8 000026 00      0   0  1
  [14] .comment          PROGBITS        00000000 020bee 000049 01  MS  0   0  1
  [15] .debug_frame      PROGBITS        00000000 020c38 000258 00      0   0  4
  [16] .symtab           SYMTAB          00000000 020e90 000900 10     17 103  4
  [17] .strtab           STRTAB          00000000 021790 000401 00      0   0  1
  [18] .shstrtab         STRTAB          00000000 021b91 0000ca 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

objcopy生成bin

$System/Tools/GNUArmToolchain/windows/bin/arm-none-eabi-objcopy.exe -O binary main.elf main.bin

objcopy can be used to generate a raw binary file by using an output target of ‘binary’ (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the load address of the lowest section copied into the output file.

elf文件包含各个sections的信息,地址信息,调试信息等。

bin文件时剔除了elf文件中的各种信息,只保留二进制汇编指令,按照LMA的顺序进行排序存储。

比如start_1 ,start_2 ,start_3的LMA,都指向IRAM1_CODE 中,按照顺序排列后生成bin。

如果

.start_1 : *(.text*) > TCM

去除AT >IRAM1_CODE,则.start_1的LMA,则指向了TCM,0x40。那么生成的bin文件将会很大,因为空洞的产生。

分析LMA VMA地址关系

总结:

1,BIN文件时按照LMA地址顺序存储,使用objcopy工具。

2,ELF文件按照VMA地址顺序存储,相当于内存映像,多用于调试。

3,If neither AT nor AT> is specified for an allocatable section,the linker will likely use VMA to determine the load address(LMA)。

以上是关于编译原理-链接实例分析的主要内容,如果未能解决你的问题,请参考以下文章

编译原理随笔

2017-2018-1 20179215《Linux内核原理与分析》第八周作业

2017-2018-1 20179202《Linux内核原理与分析》第八周作业

编译原理

2017-2018-1 20179203 《Linux内核原理与分析》第八周作业

2017-2018-1 20179209《Linux内核原理与分析》第八周作业