Hi folks, I have some comments/questions/observations about how LLD assigns flags to output sections. Maybe @smithp35 can have some ideas from the embedded perspective.
Consider the following simple scenario, that is valid for all targets (results presented for X86):
Asm file:
.globl _start, "ar"
_start:
nop
nop
nop
Linker script:
MEMORY { int_main (rx): org = 0x10000000, len = 0x00100000 }
HEAP_SIZE = 1K;
SECTIONS {
.code : { *(.text*) } > int_main
}
SECTIONS
{
.CPU0.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
.CPU1.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
.CPU2.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
}
Result using LLD:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .code PROGBITS 0000000010000000 001000 000003 00 AX 0 0 1
[ 2] .CPU0.heap NOBITS 0000000010000040 001003 000400 00 AX 0 0 64
[ 3] .CPU1.heap NOBITS 0000000010000440 001003 000400 00 AX 0 0 64
[ 4] .CPU2.heap NOBITS 0000000010000840 001003 000400 00 AX 0 0 64
...
text data bss dec hex filename
3075 0 0 3075 c03 a-lld.elf
Result: Heap allocation (just an example) has AX flags, later on, llvm-size accounts them as text sections.
Result considering Gnu ld:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .code PROGBITS 0000000010000000 001000 000003 00 AX 0 0 1
[ 2] .note.gnu.property NOTE 0000000010000008 001008 000030 00 A 0 0 8
[ 3] .CPU0.heap NOBITS 0000000010000040 001038 000400 00 WA 0 0 64
[ 4] .CPU1.heap NOBITS 0000000010000440 001038 000400 00 WA 0 0 64
[ 5] .CPU2.heap NOBITS 0000000010000840 001038 000400 00 WA 0 0 64
text data bss dec hex filename
51 0 3072 3123 c33 a-ld.elf
If we swap the assignments:
MEMORY { int_main (rx): org = 0x10000000, len = 0x00100000 }
HEAP_SIZE = 1K;
SECTIONS
{
.CPU0.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
.CPU1.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
.CPU2.heap (NOLOAD) : ALIGN(64) { . = ALIGN(64); . += HEAP_SIZE; } > int_main
}
SECTIONS {
.code : { *(.text*) } > int_main
}
We get also different flags, without X, but lld also reports as a text section (not a problem, actually):
Section Headers: Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .CPU0.heap NOBITS 0000000010000000 001000 000400 00 A 0 0 64
[ 2] .CPU1.heap NOBITS 0000000010000400 001000 000400 00 A 0 0 64
[ 3] .CPU2.heap NOBITS 0000000010000800 001000 000400 00 A 0 0 64
[ 4] .code PROGBITS 0000000010000c00 001c00 000003 00 AX 0 0 1
...
text data bss dec hex filename
3075 0 0 3075 c03 a-lld.elf
Result considering binutils ld:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .CPU0.heap NOBITS 0000000010000000 001000 000400 00 WA 0 0 64
[ 2] .CPU1.heap NOBITS 0000000010000400 001000 000400 00 WA 0 0 64
[ 3] .CPU2.heap NOBITS 0000000010000800 001000 000400 00 WA 0 0 64
[ 4] .code PROGBITS 0000000010000c00 001c00 000003 00 AX 0 0 1
text data bss dec hex filename
51 0 3072 3123 c33 a-ld.elf
My question is, is this behavior intentional? This can impact embedded development, as llvm-size
is a handy tool to evaluate code size but sometimes the result can be a bit strange.
Thank you very much.
Andreu