语法规则:
section [address] [(type)] :
[AT(lma)]
[ALIGN(section_align) | ALIGN_WITH_INPUT]
[SUBALIGN(subsection_align)]
[constraint]
{
output-section-command
output-section-command
...
} [>region] [AT>lma_region] [:phdr :phdr ...] [=fillexp] [,]
1. output section 中的 “.”为location counter, 不可以move backward
SECTIONS{
}
2. output section的assignment语法,要注意link会插入lds中未定义的section,插入的位置默认赋值语句是跟随前一个output sections
例如:
SECTIONS
{
start_of_text = . ;
.text: { *(.text) }
end_of_text = . ;
start_of_data = . ;
.data: { *(.data) }
end_of_data = . ;
}
默认插入.rodata如下:
SECTIONS
{
start_of_text = . ;
.text: { *(.text) }
end_of_text = . ;
start_of_data = . ;
.rodata: { *(.rodata) }
.data: { *(.data) }
end_of_data = . ;
}
导致start_of_data 的值并不是.data sectios的起始值,为解决这个问题,必须插入.赋值语句,link会认为是给后面的output sections设置一个新的起始地址。
如下:
SECTIONS
{
start_of_text = . ;
.text: { *(.text) }
end_of_text = . ;
. = . ;
start_of_data = . ;
.data: { *(.data) }
end_of_data = . ;
}
3. 为防止出以为,output sections尽量写成这样:
.text . : { *(.text) }
而不要写成
.text : { *(.text) }
第一种text放到当前的location counter
第二种text放到alignment最严格的地方region。所以不一定是放在当前位置。
4. AT潜规则, 如果AT和AT>都没有使用,则按照下面顺序的规则
1. 如果有指定具体的VMA地址,如 .text 0x1000 : { *(.text) _etext = . ; }, 则LMA=VMA;
2. 如果section是not allocatable的,则LMA=VMA; 比如type为OVERLAY的时候是not allocatable
3. 如果能找到能兼容当前section的memory region,且已经至少有一个section,那么LMA设置为与已经定位到该region最后一个section相同的差值(LMA和VMA)
4. 如果没有定义memory region,那么默认为region是包含所有完整的地址空间,且同样应用上面第3点
5. 如果有定义memory region,但是找不到合适属性的region,或者能找到合适的region,但是没有之前没有section定位到该region,则LMA=VMA;
5. output section address潜规则:
1. 有指定输出地址的放在指定输出地址,按照output section内部最严alignment对齐。
2. 没有指定地址的,如果有指定region,就放在该region下的free位置。
3. 如果都没有指定,从MEMROY列表中找第一个满足属性要求的memory region,放在该region的free位置
4. 如果也没有memory列表,则放在当前的location counter位置,也就是“.”的位置。
6. lds文件编写规则有2种习惯,
第1种不定义memory region,必须使用ld默认的段,比如:.text,.bss, .data, .rodata等,不使用自定义的段,不适用绝对定位
第2种定义memory region, 可以自定义section放到相应的region。可以实现绝对定位。
7. 绝对定位的方法:
代码中:
unsigned char __attribute__((section (".myBufSection"))) buf[128];
lds中:
MEMORY
{
m_interrupts (rx) : ORIGIN = 0x00000000, LENGTH = 0xC0
m_cfmprotrom (rx) : ORIGIN = 0x00000400, LENGTH = 0x10
m_text (rx) : ORIGIN = 0x00000800, LENGTH = 128K - 0x800
m_data (rwx) : ORIGIN = 0x1FFFF000, LENGTH = 16K
}
SECTIONS
{
/* placing my named section at given address: */
.myBufBlock 0x20000000 :
{
KEEP(*(.myBufSection)) /* keep my variable even if not referenced */
} > m_data
/* other placements follow here... */
}
8. 如果不使用memory语法定义region,当使用AT定位使得 则LMA != VMA; 那么同一个region的后面的section会默认顺延这种AT关系,为防止这种情况导致错误,必须在下一个section显示定义AT,使得LMA = VMA,例如N2 bos的代码lds脚本:
.dummy :
{
. = . + 0x10000;
}
.data : AT( ADDR (.dummy) )
{
__data_at_start = LOADADDR(.data);
__data_start = . ;
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
. = ALIGN(16);
__bss_start = .;
__bss_start__ = .;
.bss : AT( ADDR (.bss) )
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(. != 0 ? 16 : 1);
}
9. 哪些东西会放到bin中? 正常来说.text , .rodata; .data 这些段会放到bin中做code。可以加-R 去掉不要的段。去掉中间的段不能减少bin文件大小,如下:
$(OBJCOPY) -O binary -R .note.gnu.build-id -R .share_data $(APP).elf $(APP).bin