编译原理-链接实例分析
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)。