C代码生成可执行程序分为:预编译、编译、汇编、链接四个阶段。
- 预处理器把源程序聚合在一起,并把宏定义转换为源语言;
- 编译器根据预处理的源程序生成汇编程序;
- 汇编器处理汇编程序,生成可重定位的机器代码;
- 连接器将可重定位的目标代码和库文件连接到一起,生成可执行程序。
介绍几个常用命令,具体解释出自《The GNU linker》:
- SECTIONS命令
- MEMORY命令
- ENTRY命令
output sections:
下面是rtthread bsp下的一个连接脚本,逐字分析:
/*
* linker script for GD32F4xx with GNU ld
* bernard.xiong 2009-10-14
*/
/* Program Entry, set to mark it as "used" and avoid gc */
/* MEMORY命令,定义flash、ram的起始地址和长度,name也可改写成ROM和RAM,rx和rw表示属性,可读可执行和可读可写,ORIGIN可以写成org或o,LENGTH可以写成len或l */
MEMORY
{
CODE (rx) : ORIGIN = 0x08000000, LENGTH = 64k /* 64/512KB flash */
DATA (rw) : ORIGIN = 0x20000000, LENGTH = 256k /* 256KB sram */
}
/* entry point,也有其他写法 */
ENTRY(Reset_Handler)
/* 定义栈大小 */
_system_stack_size = 0x1000;
/* SECTIONS命令,定义了具体的flash和ram分布 */
SECTIONS
{
/* gcc在flash中主要包含text、data和bss三个section,text存放code,data存放initialized data,bss存放uninitialized data */
.text :
{
/* .表示the location counter,At the start of the ‘SECTIONS’ command, the location counter
has the value ‘0’,ALIGN(4)表示4字节对齐 */
. = ALIGN(4);
/* _stext表示text section的起始地址,在cmbacktrace中用到了_stext */
_stext = .;
/* 当垃圾回收开启时‘--gc-sections’,使用KEEP防止被清除,isr_vector在startup文件中被定义,从这里开始存放中断向量表 */
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
/* The ‘*’ is a wildcard which matches any file name. The expression ‘*(.text)’ means all ‘.text’ input sections in all input files. */
*(.text) /* remaining code */
/* 这里应该是text的结尾,怎么理解会比较好一点? */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
/* 没找到glue_7的解释 */
*(.glue_7)
*(.glue_7t)
*(.gnu.linkonce.t*)
/* section information for finsh shell */
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
/* section information for initial. */
. = ALIGN(4);
/* */
__rt_init_start = .;
/* typedef int (*init_fn_t)(void)
#define SECTION(x) __attribute__((section(x)))
#define INIT_EXPORT(fn, level) RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
init_fn_t是函数指针;
SECTION(".rti_fn." level)则表示把对象放在由括号中的名称所指代的section中;
INIT_EXPORT(rti_start, "0") => init_fn_t __rt_init_rti_start = rti_start SECTION(.rti_fn.0)
SORT is an alias for SORT_BY_NAME
实质就是将函数rti_start的首地址放到这个section中,并排序(启动顺序很重要) */
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
. = ALIGN(4);
/* cmbacktrace中用到了这个地址 */
_etext = .;
} > CODE = 0/* CODE section中 */
/* .ARM.exidx is sorted, so ha