ld: Account for .tbss size on ARM EABI targets
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
Ok for master?
--
Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
consumses VMA, then .tbss must also do so. Otherwise, a following
section such as .bss can overlap it.
Keep the existing behavior for non-EABI targets, and add tests for
static, executable, PIE, and dynamic links.
This change aligns with LLVM lld behavior for .tbss.
ld/
* ld.h: New build-time property tls_nobits_occupies_vma.
* ldlang.c: Make .tbss occupy VMA when tls_nobits_occupies_vma
is true.
* emultempl/armelf.em: Set tls_nobits_occupies_vma to true for
arm*-*-eabi* targets.
* testsuite/ld-arm/arm-elf.exp: Add new tests.
* testsuite/ld-arm/tls-app-eabi.d: New test.
* testsuite/ld-arm/tls-nobits-vma.s: New source.
* testsuite/ld-arm/tls-nobits-vma-dynamic.d: New test.
* testsuite/ld-arm/tls-nobits-vma-exec.d: New test.
* testsuite/ld-arm/tls-nobits-vma-pie.d: New test.
* testsuite/ld-arm/tls-nobits-vma-static.d: New test.
* testsuite/ld-arm/tls-nobits-vma.ld: New test.
Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
---
ld/emultempl/armelf.em | 1 +
ld/ld.h | 4 +++
ld/ldlang.c | 15 ++++++-----
ld/testsuite/ld-arm/arm-elf.exp | 18 ++++++++++---
ld/testsuite/ld-arm/tls-app-eabi.d | 18 +++++++++++++
ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d | 27 +++++++++++++++++++
ld/testsuite/ld-arm/tls-nobits-vma-exec.d | 22 +++++++++++++++
ld/testsuite/ld-arm/tls-nobits-vma-pie.d | 28 ++++++++++++++++++++
ld/testsuite/ld-arm/tls-nobits-vma-static.d | 22 +++++++++++++++
ld/testsuite/ld-arm/tls-nobits-vma.ld | 13 +++++++++
ld/testsuite/ld-arm/tls-nobits-vma.s | 11 ++++++++
11 files changed, 170 insertions(+), 9 deletions(-)
create mode 100644 ld/testsuite/ld-arm/tls-app-eabi.d
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-exec.d
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-pie.d
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-static.d
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma.ld
create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma.s
Comments
Drive-by reviewing:
On Tue, 18 Aug 2026, Torbjörn SVENSSON wrote:
> Ok for master?
>
> --
>
> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
> consumses VMA, then .tbss must also do so. Otherwise, a following
> section such as .bss can overlap it.
>
> Keep the existing behavior for non-EABI targets, and add tests for
> static, executable, PIE, and dynamic links.
>
> This change aligns with LLVM lld behavior for .tbss.
> +++ b/ld/emultempl/armelf.em
> @@ -58,6 +58,7 @@ gld${EMULATION_NAME}_before_parse (void)
> #endif /* not TARGET_ */
> input_flags.dynamic = ${DYNAMIC_LINK-true};
> config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
> + config.tls_nobits_occupies_vma = `case ${target} in arm*-*-eabi*) echo true ;; *) echo false ;; esac`;
Can $target be "thumb" here, so it'd make sense to have the
pattern instead be "*-*-eabi*"?
(Not a rhetorical question, if $target is somehow canonicalized
to "arm" and a lone "*-*-eabi*" would look out of place here
rather than obviously safe.)
brgds, H-P
On 2026-08-19 05:57, Hans-Peter Nilsson wrote:
> Drive-by reviewing:
>
> On Tue, 18 Aug 2026, Torbjörn SVENSSON wrote:
>
>> Ok for master?
>>
>> --
>>
>> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
>> consumses VMA, then .tbss must also do so. Otherwise, a following
>> section such as .bss can overlap it.
>>
>> Keep the existing behavior for non-EABI targets, and add tests for
>> static, executable, PIE, and dynamic links.
>>
>> This change aligns with LLVM lld behavior for .tbss.
>
>> +++ b/ld/emultempl/armelf.em
>> @@ -58,6 +58,7 @@ gld${EMULATION_NAME}_before_parse (void)
>> #endif /* not TARGET_ */
>> input_flags.dynamic = ${DYNAMIC_LINK-true};
>> config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
>> + config.tls_nobits_occupies_vma = `case ${target} in arm*-*-eabi*) echo true ;; *) echo false ;; esac`;
>
> Can $target be "thumb" here, so it'd make sense to have the
> pattern instead be "*-*-eabi*"?
>
> (Not a rhetorical question, if $target is somehow canonicalized
> to "arm" and a lone "*-*-eabi*" would look out of place here
> rather than obviously safe.)
I've never seen any "thumb" target like that, and greping the sources only gives me hits in changelog entries.
Is this some old relic or is it actually used these days?
In the GCC sources, I see that thumb-*-* is listed as "not supported".
Do you still think I should add 'thumb*-*-eabi*" or something similar?
Kind regards,
Torbjörn
On Wed, 19 Aug 2026, Torbjorn SVENSSON wrote:
> > Can $target be "thumb" here, so it'd make sense to have the
> > pattern instead be "*-*-eabi*"?
> >
> > (Not a rhetorical question, if $target is somehow canonicalized
> > to "arm" and a lone "*-*-eabi*" would look out of place here
> > rather than obviously safe.)
>
> I've never seen any "thumb" target like that, and greping the sources only
> gives me hits in changelog entries.
> Is this some old relic or is it actually used these days?
>
> In the GCC sources, I see that thumb-*-* is listed as "not supported".
>
> Do you still think I should add 'thumb*-*-eabi*" or something similar?
Above, I suggested "*-*-eabi*" if you're in known ARM-only
context.
But, I don't know, like you I've only seen it in configure
scripts and never used it myself. Also, it was just an example.
I see config.sub has "strongarm-*" and "thumb-*" too, but maybe
that's not a complete list. I'll defer the question to a
suitable maintainer.
brgds, H-P
Gentle ping! :)
Kind regards,
Torbjörn
On 2026-08-18 11:32, Torbjörn SVENSSON wrote:
> Ok for master?
>
> --
>
> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
> consumses VMA, then .tbss must also do so. Otherwise, a following
> section such as .bss can overlap it.
>
> Keep the existing behavior for non-EABI targets, and add tests for
> static, executable, PIE, and dynamic links.
>
> This change aligns with LLVM lld behavior for .tbss.
>
> ld/
>
> * ld.h: New build-time property tls_nobits_occupies_vma.
> * ldlang.c: Make .tbss occupy VMA when tls_nobits_occupies_vma
> is true.
> * emultempl/armelf.em: Set tls_nobits_occupies_vma to true for
> arm*-*-eabi* targets.
> * testsuite/ld-arm/arm-elf.exp: Add new tests.
> * testsuite/ld-arm/tls-app-eabi.d: New test.
> * testsuite/ld-arm/tls-nobits-vma.s: New source.
> * testsuite/ld-arm/tls-nobits-vma-dynamic.d: New test.
> * testsuite/ld-arm/tls-nobits-vma-exec.d: New test.
> * testsuite/ld-arm/tls-nobits-vma-pie.d: New test.
> * testsuite/ld-arm/tls-nobits-vma-static.d: New test.
> * testsuite/ld-arm/tls-nobits-vma.ld: New test.
>
> Signed-off-by: Torbjörn SVENSSON <torbjorn.svensson@foss.st.com>
> ---
> ld/emultempl/armelf.em | 1 +
> ld/ld.h | 4 +++
> ld/ldlang.c | 15 ++++++-----
> ld/testsuite/ld-arm/arm-elf.exp | 18 ++++++++++---
> ld/testsuite/ld-arm/tls-app-eabi.d | 18 +++++++++++++
> ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d | 27 +++++++++++++++++++
> ld/testsuite/ld-arm/tls-nobits-vma-exec.d | 22 +++++++++++++++
> ld/testsuite/ld-arm/tls-nobits-vma-pie.d | 28 ++++++++++++++++++++
> ld/testsuite/ld-arm/tls-nobits-vma-static.d | 22 +++++++++++++++
> ld/testsuite/ld-arm/tls-nobits-vma.ld | 13 +++++++++
> ld/testsuite/ld-arm/tls-nobits-vma.s | 11 ++++++++
> 11 files changed, 170 insertions(+), 9 deletions(-)
> create mode 100644 ld/testsuite/ld-arm/tls-app-eabi.d
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-exec.d
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-pie.d
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma-static.d
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma.ld
> create mode 100644 ld/testsuite/ld-arm/tls-nobits-vma.s
>
> diff --git a/ld/emultempl/armelf.em b/ld/emultempl/armelf.em
> index f70bcf34b8b..9e59f7ceb94 100644
> --- a/ld/emultempl/armelf.em
> +++ b/ld/emultempl/armelf.em
> @@ -58,6 +58,7 @@ gld${EMULATION_NAME}_before_parse (void)
> #endif /* not TARGET_ */
> input_flags.dynamic = ${DYNAMIC_LINK-true};
> config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
> + config.tls_nobits_occupies_vma = `case ${target} in arm*-*-eabi*) echo true ;; *) echo false ;; esac`;
> config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo true ; else echo false ; fi`;
> EOF
> if test -n "$COMMONPAGESIZE"; then
> diff --git a/ld/ld.h b/ld/ld.h
> index 76825e4253c..8f83a9da4d1 100644
> --- a/ld/ld.h
> +++ b/ld/ld.h
> @@ -236,6 +236,10 @@ typedef struct
> parameter. */
> bool has_shared;
>
> + /* If TRUE, TLS NOBITS sections consume VMA like other allocated
> + sections. */
> + bool tls_nobits_occupies_vma;
> +
> /* If TRUE, build constructors. */
> bool build_constructors;
>
> diff --git a/ld/ldlang.c b/ld/ldlang.c
> index 65494acca00..35b884bd98a 100644
> --- a/ld/ldlang.c
> +++ b/ld/ldlang.c
> @@ -5890,8 +5890,11 @@ sort_sections_by_vma (const void *arg1, const void *arg2)
> #define IS_TBSS(s) \
> ((s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == SEC_THREAD_LOCAL)
>
> +#define TBSS_EFFECTIVELY_ZERO(s) \
> + (IS_TBSS (s) && !config.tls_nobits_occupies_vma)
> +
> #define IGNORE_SECTION(s) \
> - ((s->flags & SEC_ALLOC) == 0 || IS_TBSS (s))
> + ((s->flags & SEC_ALLOC) == 0 || TBSS_EFFECTIVELY_ZERO (s))
>
> /* Check to see if any allocated sections overlap with other allocated
> sections. This can happen if a linker script specifies the output
> @@ -6433,8 +6436,8 @@ lang_size_sections_1
> if (bfd_is_abs_section (os->bfd_section) || os->ignored)
> break;
>
> - /* .tbss sections effectively have zero size. */
> - if (!IS_TBSS (os->bfd_section)
> + /* Hosted .tbss sections effectively have zero size. */
> + if (!TBSS_EFFECTIVELY_ZERO (os->bfd_section)
> || bfd_link_relocatable (&link_info))
> dotdelta = TO_ADDR (os->bfd_section->size);
> else
> @@ -6813,7 +6816,7 @@ lang_size_relro_segment_1 (void)
> bfd_vma start, end, bump;
>
> end = start = sec->vma;
> - if (!IS_TBSS (sec))
> + if (!TBSS_EFFECTIVELY_ZERO (sec))
> end += TO_ADDR (sec->size);
> bump = desired_end - end;
> /* We'd like to increase START by BUMP, but we must heed
> @@ -6936,8 +6939,8 @@ lang_do_assignments_1 (lang_statement_union_type *s,
> {
> newdot = os->bfd_section->vma;
>
> - /* .tbss sections effectively have zero size. */
> - if (!IS_TBSS (os->bfd_section)
> + /* Hosted .tbss sections effectively have zero size. */
> + if (!TBSS_EFFECTIVELY_ZERO (os->bfd_section)
> || bfd_link_relocatable (&link_info))
> newdot += TO_ADDR (os->bfd_section->size);
>
> diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
> index ad27c1f86c9..5b5906e10ee 100644
> --- a/ld/testsuite/ld-arm/arm-elf.exp
> +++ b/ld/testsuite/ld-arm/arm-elf.exp
> @@ -120,20 +120,25 @@ set tmp {
> "arm-call"}
> }
> append armelftests_common $tmp
> -set tmp {
> +if {[istarget "arm*-*-eabi*"]} {
> + set tls_app_dump tls-app-eabi.d
> +} else {
> + set tls_app_dump tls-app.d
> +}
> +set tmp [subst -nocommands -nobackslashes {
> {"TLS shared library" "-shared -T arm-lib.ld --hash-style=sysv" ""
> "" {tls-lib.s}
> {{objdump -fdw tls-lib.d} {objdump -Rw tls-lib.r}}
> "tls-lib.so"}
> {"TLS dynamic application"
> "-T arm-dyn.ld --hash-style=sysv tmpdir/tls-lib.so" "" "" {tls-app.s}
> - {{objdump -fdw tls-app.d} {objdump -Rw tls-app.r}}
> + {{objdump -fdw $tls_app_dump} {objdump -Rw tls-app.r}}
> "tls-app"}
> {"TLS gnu shared library got"
> "-shared -T arm-dyn.ld --hash-style=sysv" "" "" {tls-gdesc-got.s}
> {{objdump "-fDR -j .got" tls-gdesc-got.d}}
> "tls-lib2-got.so"}
> -}
> +}]
> if [check_shared_lib_support] { append armelftests_common $tmp }
> set tmp {
> {"TLS gnu GD to IE relaxation"
> @@ -432,6 +437,13 @@ run_dump_test "rel32-reject"
> run_dump_test "rel32-reject-pie"
> run_dump_test "pie-bind-locally"
>
> +if {[istarget "arm*-*-eabi*"]} {
> + run_dump_test "tls-nobits-vma-static"
> + run_dump_test "tls-nobits-vma-exec"
> + run_dump_test "tls-nobits-vma-pie"
> + run_dump_test "tls-nobits-vma-dynamic"
> +}
> +
> # Exclude non-ARM-EABI targets.
>
> if { [istarget "arm*-*-netbsd*"] } {
> diff --git a/ld/testsuite/ld-arm/tls-app-eabi.d b/ld/testsuite/ld-arm/tls-app-eabi.d
> new file mode 100644
> index 00000000000..d240a0ecbaa
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-app-eabi.d
> @@ -0,0 +1,18 @@
> +
> +.*: file format elf32-.*arm.*
> +architecture: arm.*, flags 0x00000112:
> +EXEC_P, HAS_SYMS, D_PAGED
> +start address 0x00008[0-9a-f]+
> +
> +Disassembly of section .text:
> +
> +00008[0-9a-f]+ <foo>:
> + 8[0-9a-f]+: e1a00000 nop @ \(mov r0, r0\)
> + 8[0-9a-f]+: e1a00000 nop @ \(mov r0, r0\)
> + 8[0-9a-f]+: e1a0f00e mov pc, lr
> + 8[0-9a-f]+: 000080c4 .word 0x000080c4
> + 8[0-9a-f]+: 000080bc .word 0x000080bc
> + 8[0-9a-f]+: 000080b4 .word 0x000080b4
> + 8[0-9a-f]+: 00000004 .word 0x00000004
> + 8[0-9a-f]+: 000080cc .word 0x000080cc
> + 8[0-9a-f]+: 00000014 .word 0x00000014
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d b/ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d
> new file mode 100644
> index 00000000000..3c8e8930656
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma-dynamic.d
> @@ -0,0 +1,27 @@
> +#source: tls-nobits-vma.s
> +#ld: -shared -T tls-nobits-vma.ld
> +#readelf: -hSW
> +
> +ELF Header:
> +#...
> + Type: +DYN \(Shared object file\)
> +#...
> +
> +Section Headers:
> + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
> + \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
> + \[ 1\] .dynsym +DYNSYM +00008000 +[0-9a-f]+ +000010 +10 +A +2 +1 +4
> + \[ 2\] .dynstr +STRTAB +00008010 +[0-9a-f]+ +000001 +00 +A +0 +0 +1
> + \[ 3\] .hash +HASH +00008014 +[0-9a-f]+ +000010 +04 +A +1 +0 +4
> + \[ 4\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
> + \[ 5\] .dynamic +DYNAMIC +00001004 +[0-9a-f]+ +000058 +08 +WA +2 +0 +4
> + \[ 6\] .got.plt +PROGBITS +0000105c +[0-9a-f]+ +00000c +04 +WA +0 +0 +4
> + \[ 7\] .tdata +PROGBITS +00001068 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 8\] .tbss +NOBITS +0000106c +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 9\] .bss +NOBITS +00001070 +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
> + \[10\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[11\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +12 +[0-9]+ +4
> + \[12\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[13\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> +Key to Flags:
> +#...
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma-exec.d b/ld/testsuite/ld-arm/tls-nobits-vma-exec.d
> new file mode 100644
> index 00000000000..adf00663084
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma-exec.d
> @@ -0,0 +1,22 @@
> +#source: tls-nobits-vma.s
> +#ld: -T tls-nobits-vma.ld
> +#readelf: -hSW
> +
> +ELF Header:
> +#...
> + Type: +EXEC \(Executable file\)
> +#...
> +
> +Section Headers:
> + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
> + \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
> + \[ 1\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
> + \[ 2\] .tdata +PROGBITS +00001004 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 3\] .tbss +NOBITS +00001008 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 4\] .bss +NOBITS +0000100c +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
> + \[ 5\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[ 6\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +7 +[0-9]+ +4
> + \[ 7\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[ 8\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> +Key to Flags:
> +#...
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma-pie.d b/ld/testsuite/ld-arm/tls-nobits-vma-pie.d
> new file mode 100644
> index 00000000000..9fbcde5b491
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma-pie.d
> @@ -0,0 +1,28 @@
> +#source: tls-nobits-vma.s
> +#ld: -pie -T tls-nobits-vma.ld
> +#readelf: -hSW
> +
> +ELF Header:
> +#...
> + Type: +EXEC \(Executable file\)
> +#...
> +
> +Section Headers:
> + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
> + \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
> + \[ 1\] .interp +PROGBITS +00008000 +[0-9a-f]+ +000011 +00 +A +0 +0 +1
> + \[ 2\] .dynsym +DYNSYM +00008014 +[0-9a-f]+ +000010 +10 +A +3 +1 +4
> + \[ 3\] .dynstr +STRTAB +00008024 +[0-9a-f]+ +000001 +00 +A +0 +0 +1
> + \[ 4\] .hash +HASH +00008028 +[0-9a-f]+ +000010 +04 +A +2 +0 +4
> + \[ 5\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
> + \[ 6\] .dynamic +DYNAMIC +00001004 +[0-9a-f]+ +000068 +08 +WA +3 +0 +4
> + \[ 7\] .got.plt +PROGBITS +0000106c +[0-9a-f]+ +00000c +04 +WA +0 +0 +4
> + \[ 8\] .tdata +PROGBITS +00001078 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 9\] .tbss +NOBITS +0000107c +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[10\] .bss +NOBITS +00001080 +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
> + \[11\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[12\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +13 +[0-9]+ +4
> + \[13\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[14\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> +Key to Flags:
> +#...
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma-static.d b/ld/testsuite/ld-arm/tls-nobits-vma-static.d
> new file mode 100644
> index 00000000000..7e3cdb9159d
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma-static.d
> @@ -0,0 +1,22 @@
> +#source: tls-nobits-vma.s
> +#ld: -static -T tls-nobits-vma.ld
> +#readelf: -hSW
> +
> +ELF Header:
> +#...
> + Type: +EXEC \(Executable file\)
> +#...
> +
> +Section Headers:
> + \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
> + \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
> + \[ 1\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
> + \[ 2\] .tdata +PROGBITS +00001004 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 3\] .tbss +NOBITS +00001008 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
> + \[ 4\] .bss +NOBITS +0000100c +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
> + \[ 5\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[ 6\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +7 +[0-9]+ +4
> + \[ 7\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> + \[ 8\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
> +Key to Flags:
> +#...
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma.ld b/ld/testsuite/ld-arm/tls-nobits-vma.ld
> new file mode 100644
> index 00000000000..14c1527e401
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma.ld
> @@ -0,0 +1,13 @@
> +MEMORY
> +{
> + FLASH (rx) : ORIGIN = 0x8000, LENGTH = 0x1000
> + RAM (rw) : ORIGIN = 0x1000, LENGTH = 0x1000
> +}
> +
> +SECTIONS
> +{
> + .data : ALIGN(4) { *(.data) } >RAM AT>FLASH
> + .tdata : ALIGN(4) { *(.tdata) } >RAM AT>FLASH
> + .tbss (NOLOAD) : ALIGN(4) { *(.tbss) } >RAM
> + .bss (NOLOAD) : ALIGN(4) { *(.bss) } >RAM
> +}
> diff --git a/ld/testsuite/ld-arm/tls-nobits-vma.s b/ld/testsuite/ld-arm/tls-nobits-vma.s
> new file mode 100644
> index 00000000000..df2607251b1
> --- /dev/null
> +++ b/ld/testsuite/ld-arm/tls-nobits-vma.s
> @@ -0,0 +1,11 @@
> + .section .data,"aw",%progbits
> + .word 1
> +
> + .section .tdata,"awT",%progbits
> + .word 2
> +
> + .section .tbss,"awT",%nobits
> + .space 4
> +
> + .section .bss,"aw",%nobits
> + .space 8
On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
> > Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
> > consumses VMA, then .tbss must also do so. Otherwise, a following
> > section such as .bss can overlap it.
In other words, the loader is broken for TLS. Why break the linker as
well?
On 2026-08-29 09:35, Alan Modra wrote:
> On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
>>> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
>>> consumses VMA, then .tbss must also do so. Otherwise, a following
>>> section such as .bss can overlap it.
>
> In other words, the loader is broken for TLS. Why break the linker as
> well?
>
What loader?
I'm taking about bare-metal, i.e. there is nothing doing any loading.
The CPU is executing straight from flash without any ram copy of the
program or similar loader activities that normally exist on a pc.
Kind regards,
Torbjörn
On Sat, Aug 29, 2026 at 09:46:23AM +0200, Torbjorn SVENSSON wrote:
>
>
> On 2026-08-29 09:35, Alan Modra wrote:
> > On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
> > > > Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
> > > > consumses VMA, then .tbss must also do so. Otherwise, a following
> > > > section such as .bss can overlap it.
> >
> > In other words, the loader is broken for TLS. Why break the linker as
> > well?
> >
>
> What loader?
> I'm taking about bare-metal, i.e. there is nothing doing any loading.
> The CPU is executing straight from flash without any ram copy of the
> program or similar loader activities that normally exist on a pc.
Yes, TLS is not supported there. How do you expect it is supposed to
work?
On 2026-08-30 11:49, Alan Modra wrote:
> On Sat, Aug 29, 2026 at 09:46:23AM +0200, Torbjorn SVENSSON wrote:
>>
>>
>> On 2026-08-29 09:35, Alan Modra wrote:
>>> On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
>>>>> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
>>>>> consumses VMA, then .tbss must also do so. Otherwise, a following
>>>>> section such as .bss can overlap it.
>>>
>>> In other words, the loader is broken for TLS. Why break the linker as
>>> well?
>>>
>>
>> What loader?
>> I'm taking about bare-metal, i.e. there is nothing doing any loading.
>> The CPU is executing straight from flash without any ram copy of the
>> program or similar loader activities that normally exist on a pc.
>
> Yes, TLS is not supported there. How do you expect it is supposed to
> work?
>
Arm decided to enable TLS for their arm-none-eabi toolchain in this commit:
https://gitlab.arm.com/tooling/gnu-devtools-for-arm/-/commit/f6a8633309c850d62817859986a165c94f11babf
To my understanding, the local-exec TLS mode should be supported for
bare-metal targets. In this mode, the memory block for TLS would be
allocated while linking the application and thus, when the application
boots, it will only need to do the initialization of .tbss and .tdata,
just like .bss and .data, for the initial thread. Any additional thread
would allocate it's own block of memory and again initialize the values
from what was stored in flash / clear the region that should be cleared.
Does this make sense or am I totally missing something here?
Note, LLVM linker already has this behavior. From some testing, it looks
like LLVM linker has the same output, regardless if linking for
bare-metal or PC. I think that the solution that binutils has is
correct for PC, but not for bare-metal, hence my suggestion for special
handling.
Kind regards,
Torbjörn
On Mon, Aug 31, 2026 at 10:21:16AM +0200, Torbjorn SVENSSON wrote:
>
>
> On 2026-08-30 11:49, Alan Modra wrote:
> > On Sat, Aug 29, 2026 at 09:46:23AM +0200, Torbjorn SVENSSON wrote:
> > >
> > >
> > > On 2026-08-29 09:35, Alan Modra wrote:
> > > > On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
> > > > > > Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
> > > > > > consumses VMA, then .tbss must also do so. Otherwise, a following
> > > > > > section such as .bss can overlap it.
> > > >
> > > > In other words, the loader is broken for TLS. Why break the linker as
> > > > well?
> > > >
> > >
> > > What loader?
> > > I'm taking about bare-metal, i.e. there is nothing doing any loading.
> > > The CPU is executing straight from flash without any ram copy of the
> > > program or similar loader activities that normally exist on a pc.
> >
> > Yes, TLS is not supported there. How do you expect it is supposed to
> > work?
> >
>
> Arm decided to enable TLS for their arm-none-eabi toolchain in this commit:
> https://gitlab.arm.com/tooling/gnu-devtools-for-arm/-/commit/f6a8633309c850d62817859986a165c94f11babf
>
> To my understanding, the local-exec TLS mode should be supported for
> bare-metal targets. In this mode, the memory block for TLS would be
> allocated while linking the application and thus, when the application
> boots, it will only need to do the initialization of .tbss and .tdata,
> just like .bss and .data, for the initial thread. Any additional thread
> would allocate it's own block of memory and again initialize the values
> from what was stored in flash / clear the region that should be cleared.
>
> Does this make sense or am I totally missing something here?
.tdata is not supposed to be used directly by the first thread. It is
for initialisation of each thread's TLS and must be kept pristine.
That's why it doesn't make much sense for the first thread to use it
directly, or to allocate vma space for .tbss.
I doubt very much your target systems are running out of flash for
very long. Even back when I was designing hardware, support chips in
the mid 80s were starting to provide RAM shadowing of ROM. The system
only ran out of ROM until it was copied to RAM, at which point the RAM
shadow took over. ROM was *much* slower, not only due to a slower
access time but also due to the support chips allowing it to be 8-bit
memory when main memory was 32-bit. I haven't been in the hardware
game for a long time, but I expect the speed difference between ROM
and RAM still holds. Which means you wouldn't want to access ROM for
a pristine copy of .tdata when setting up the second thread (and you
might not even be able to access ROM again without a reboot).
The only case I can see where using .tdata/.tbss directly makes sense
is when you in fact have only one thread, but you stupidly enabled
threads or your software accidentally pulls in some library with
thread support, *and* your bootup code doesn't understand TLS. In
that case I think you could link with this little extra script
SECTIONS {
.bogustls : { *(.tdata) *(.tbss) LONG (0); }
}
which would more or less do the same as your patch.
> Note, LLVM linker already has this behavior.
That is likely just a bug, I think.
> From some testing, it looks
> like LLVM linker has the same output, regardless if linking for
> bare-metal or PC. I think that the solution that binutils has is
> correct for PC, but not for bare-metal, hence my suggestion for special
> handling.
>
> Kind regards,
> Torbjörn
Hi Alan,
Thanks for the reply.
On 2026-09-01 01:33, Alan Modra wrote:
> On Mon, Aug 31, 2026 at 10:21:16AM +0200, Torbjorn SVENSSON wrote:
>>
>>
>> On 2026-08-30 11:49, Alan Modra wrote:
>>> On Sat, Aug 29, 2026 at 09:46:23AM +0200, Torbjorn SVENSSON wrote:
>>>>
>>>>
>>>> On 2026-08-29 09:35, Alan Modra wrote:
>>>>> On Fri, Aug 28, 2026 at 03:10:09PM +0200, Torbjorn SVENSSON wrote:
>>>>>>> Bare-metal ARM EABI programs allocate TLS storage directly, so if .tdata
>>>>>>> consumses VMA, then .tbss must also do so. Otherwise, a following
>>>>>>> section such as .bss can overlap it.
>>>>>
>>>>> In other words, the loader is broken for TLS. Why break the linker as
>>>>> well?
>>>>>
>>>>
>>>> What loader?
>>>> I'm taking about bare-metal, i.e. there is nothing doing any loading.
>>>> The CPU is executing straight from flash without any ram copy of the
>>>> program or similar loader activities that normally exist on a pc.
>>>
>>> Yes, TLS is not supported there. How do you expect it is supposed to
>>> work?
>>>
>>
>> Arm decided to enable TLS for their arm-none-eabi toolchain in this commit:
>> https://gitlab.arm.com/tooling/gnu-devtools-for-arm/-/commit/f6a8633309c850d62817859986a165c94f11babf
>>
>> To my understanding, the local-exec TLS mode should be supported for
>> bare-metal targets. In this mode, the memory block for TLS would be
>> allocated while linking the application and thus, when the application
>> boots, it will only need to do the initialization of .tbss and .tdata,
>> just like .bss and .data, for the initial thread. Any additional thread
>> would allocate it's own block of memory and again initialize the values
>> from what was stored in flash / clear the region that should be cleared.
>>
>> Does this make sense or am I totally missing something here?
>
> .tdata is not supposed to be used directly by the first thread. It is
> for initialisation of each thread's TLS and must be kept pristine.
> That's why it doesn't make much sense for the first thread to use it
> directly, or to allocate vma space for .tbss.
Please consider this simplified version of the linker script that we use
for our STM32F407VG device that we manufacture.
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
}
SECTIONS
{
.text :
{
*(.text)
...
} >FLASH
_sidata = LOADADDR(.data);
.data : ALIGN(4)
{
_sdata = .;
*(.data)
...
_edata = .;
} >RAM AT> FLASH
_sitdata = LOADADDR(.tdata);
.tdata : ALIGN(4)
{
_stdata = .;
*(.tdata)
...
_etdata = .;
} >RAM AT> FLASH
.tbss (NOLOAD) : ALIGN(4)
{
_stbss = .;
*(.tbss)
...
_etbss = .;
} >RAM
.bss (NOLOAD) : ALIGN(4)
{
_sbss = .;
*(.bss)
...
_ebss = .;
} >RAM
}
As you can see, we have a pristine copy of .tdata in FLASH and another
copy in RAM that the program is working on. Whenever there would be a
second thread, the data would be copied from flash again and that
would ensure that the initial values are correct.
There needs to be no special treatment for .tbss, since the only thing
required are the lengths (to know how much RAM to clear).
>
> I doubt very much your target systems are running out of flash for
> very long. Even back when I was designing hardware, support chips in
> the mid 80s were starting to provide RAM shadowing of ROM. The system
> only ran out of ROM until it was copied to RAM, at which point the RAM
> shadow took over. ROM was *much* slower, not only due to a slower
> access time but also due to the support chips allowing it to be 8-bit
> memory when main memory was 32-bit. I haven't been in the hardware
> game for a long time, but I expect the speed difference between ROM
> and RAM still holds. Which means you wouldn't want to access ROM for
> a pristine copy of .tdata when setting up the second thread (and you
> might not even be able to access ROM again without a reboot).
In the Arm Cortex-M world, there are speed differences between RAM and
ROM, just like you explain, but the pipeline limits the impact of it.
RAM is far more expensive than FLASH(ROM). As you can see in the linker
script above, flash is about 10 times bigger than RAM. To allow the
entire application to fit in RAM, plus the working data itself, then,
RAM would always need to be bigger than FLASH. Building such a device
would be possible, but very expensive.
Generally speaking, the wear on flash for reading is low and I've not
heard of anyone having issues running straight from flash for extensive
amount of time. What does kill an embedded devices is reprogramming the
flash.
>
> The only case I can see where using .tdata/.tbss directly makes sense
> is when you in fact have only one thread, but you stupidly enabled
> threads or your software accidentally pulls in some library with
> thread support, *and* your bootup code doesn't understand TLS. In
> that case I think you could link with this little extra script
>
> SECTIONS {
> .bogustls : { *(.tdata) *(.tbss) LONG (0); }
> }
>
> which would more or less do the same as your patch.
Not sure if this helps you, but you can see how picolibc decided
to implement TLS support here:
https://github.com/picolibc/picolibc/blob/main/doc/tls.md
Here is also my patch to newlib, where I request to import this
implementation into newlib itself:
https://sourceware.org/pipermail/newlib/2026/022606.html
What is important for embedded, is to avoid malloc for the initial
thread if possible. The reason is that malloc is usually not supposed
to exist in embedded applications for security purposes.
It's also pointed out in the commit message from Arm here:
https://gitlab.arm.com/tooling/gnu-devtools-for-arm/-/commit/f6a8633309c850d62817859986a165c94f11babf
Remove --disable-tls so that GCC emits ELF TLS relocations instead of
using the emulated TLS runtime. This avoids malloc-based emulation and
makes _Thread_local usable in bare-metal environments.
>> Note, LLVM linker already has this behavior.
>
> That is likely just a bug, I think.
>
>> From some testing, it looks
>> like LLVM linker has the same output, regardless if linking for
>> bare-metal or PC. I think that the solution that binutils has is
>> correct for PC, but not for bare-metal, hence my suggestion for special
>> handling.
>>
>> Kind regards,
>> Torbjörn
>
Kind regards,
Torbjörn
On Tue, Sep 01, 2026 at 10:28:06AM +0200, Torbjorn SVENSSON wrote:
> Please consider this simplified version of the linker script that we use
> for our STM32F407VG device that we manufacture.
>
> MEMORY
> {
> FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
> RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
> }
>
> SECTIONS
> {
> .text :
> {
> *(.text)
> ...
> } >FLASH
>
> _sidata = LOADADDR(.data);
> .data : ALIGN(4)
> {
> _sdata = .;
> *(.data)
> ...
> _edata = .;
> } >RAM AT> FLASH
>
> _sitdata = LOADADDR(.tdata);
> .tdata : ALIGN(4)
> {
> _stdata = .;
> *(.tdata)
> ...
> _etdata = .;
> } >RAM AT> FLASH
>
> .tbss (NOLOAD) : ALIGN(4)
> {
> _stbss = .;
> *(.tbss)
> ...
> _etbss = .;
> } >RAM
>
> .bss (NOLOAD) : ALIGN(4)
> {
> _sbss = .;
> *(.bss)
> ...
> _ebss = .;
> } >RAM
> }
>
> As you can see, we have a pristine copy of .tdata in FLASH and another
> copy in RAM that the program is working on. Whenever there would be a
> second thread, the data would be copied from flash again and that
> would ensure that the initial values are correct.
> There needs to be no special treatment for .tbss, since the only thing
> required are the lengths (to know how much RAM to clear).
>
> >
> > I doubt very much your target systems are running out of flash for
> > very long. Even back when I was designing hardware, support chips in
> > the mid 80s were starting to provide RAM shadowing of ROM. The system
> > only ran out of ROM until it was copied to RAM, at which point the RAM
> > shadow took over. ROM was *much* slower, not only due to a slower
> > access time but also due to the support chips allowing it to be 8-bit
> > memory when main memory was 32-bit. I haven't been in the hardware
> > game for a long time, but I expect the speed difference between ROM
> > and RAM still holds. Which means you wouldn't want to access ROM for
> > a pristine copy of .tdata when setting up the second thread (and you
> > might not even be able to access ROM again without a reboot).
>
> In the Arm Cortex-M world, there are speed differences between RAM and
> ROM, just like you explain, but the pipeline limits the impact of it.
> RAM is far more expensive than FLASH(ROM). As you can see in the linker
> script above, flash is about 10 times bigger than RAM. To allow the
> entire application to fit in RAM, plus the working data itself, then,
> RAM would always need to be bigger than FLASH. Building such a device
> would be possible, but very expensive.
OK, wrong assumption on my part. I haven't worked as an electronics
engineer for a very long time..
So back to your patch, which is starting to make more sense. I could
take the position that your script can be modified to force .tbss to
occupy space. That's just a matter of setting the .bss start vma with
something like:
.bss ALIGN (ADDR (.tbss) + SIZEOF (.tbss), 4) (NOLOAD) :
As far as script vma tweaks go it's not too horrible, cf. .branch_lt
in emulparams/elf64ppc.sh. This should only fail if there happens to
be an orphan section inserted between .tbss and .bss. (You'd need a
.tbss style section that didn't match any of the input section
wildcards in .tbss, so very unlikely.) Doing it this way also has the
benefit that it should work with any version of GNU ld.
On the other hand, this variation of TLS might be generally useful in
embedded systems. So if you want to go ahead with your patch I'd like
to see tls_nobits_occupies_vma set from ${EMBEDDED} rather than a
target test. This will mean you are probably better off modifying
tls-app.d to allow both sets of numbers rather than specifying all the
target triples that have targ_emul=armelf to use tls-app-eabi.d.
While you're at that, replace the ".word 0x000080bc" and
similar with ".*".
On 2026-09-02 10:20, Alan Modra wrote:
> On Tue, Sep 01, 2026 at 10:28:06AM +0200, Torbjorn SVENSSON wrote:
>> Please consider this simplified version of the linker script that we use
>> for our STM32F407VG device that we manufacture.
>>
>> MEMORY
>> {
>> FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
>> RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
>> }
>>
>> SECTIONS
>> {
>> .text :
>> {
>> *(.text)
>> ...
>> } >FLASH
>>
>> _sidata = LOADADDR(.data);
>> .data : ALIGN(4)
>> {
>> _sdata = .;
>> *(.data)
>> ...
>> _edata = .;
>> } >RAM AT> FLASH
>>
>> _sitdata = LOADADDR(.tdata);
>> .tdata : ALIGN(4)
>> {
>> _stdata = .;
>> *(.tdata)
>> ...
>> _etdata = .;
>> } >RAM AT> FLASH
>>
>> .tbss (NOLOAD) : ALIGN(4)
>> {
>> _stbss = .;
>> *(.tbss)
>> ...
>> _etbss = .;
>> } >RAM
>>
>> .bss (NOLOAD) : ALIGN(4)
>> {
>> _sbss = .;
>> *(.bss)
>> ...
>> _ebss = .;
>> } >RAM
>> }
>>
>> As you can see, we have a pristine copy of .tdata in FLASH and another
>> copy in RAM that the program is working on. Whenever there would be a
>> second thread, the data would be copied from flash again and that
>> would ensure that the initial values are correct.
>> There needs to be no special treatment for .tbss, since the only thing
>> required are the lengths (to know how much RAM to clear).
>>
>>>
>>> I doubt very much your target systems are running out of flash for
>>> very long. Even back when I was designing hardware, support chips in
>>> the mid 80s were starting to provide RAM shadowing of ROM. The system
>>> only ran out of ROM until it was copied to RAM, at which point the RAM
>>> shadow took over. ROM was *much* slower, not only due to a slower
>>> access time but also due to the support chips allowing it to be 8-bit
>>> memory when main memory was 32-bit. I haven't been in the hardware
>>> game for a long time, but I expect the speed difference between ROM
>>> and RAM still holds. Which means you wouldn't want to access ROM for
>>> a pristine copy of .tdata when setting up the second thread (and you
>>> might not even be able to access ROM again without a reboot).
>>
>> In the Arm Cortex-M world, there are speed differences between RAM and
>> ROM, just like you explain, but the pipeline limits the impact of it.
>> RAM is far more expensive than FLASH(ROM). As you can see in the linker
>> script above, flash is about 10 times bigger than RAM. To allow the
>> entire application to fit in RAM, plus the working data itself, then,
>> RAM would always need to be bigger than FLASH. Building such a device
>> would be possible, but very expensive.
>
> OK, wrong assumption on my part. I haven't worked as an electronics
> engineer for a very long time..
>
> So back to your patch, which is starting to make more sense. I could
> take the position that your script can be modified to force .tbss to
> occupy space. That's just a matter of setting the .bss start vma with
> something like:
>
> .bss ALIGN (ADDR (.tbss) + SIZEOF (.tbss), 4) (NOLOAD) :
>
> As far as script vma tweaks go it's not too horrible, cf. .branch_lt
> in emulparams/elf64ppc.sh. This should only fail if there happens to
> be an orphan section inserted between .tbss and .bss. (You'd need a
> .tbss style section that didn't match any of the input section
> wildcards in .tbss, so very unlikely.) Doing it this way also has the
> benefit that it should work with any version of GNU ld.
I tried this approach before sending the patch and it sort of works for
some targets. One target that does fail is Cortex-A7, not because it
behaves differently, but rather because QEMU for Cortex-A7 is different
than for Cortex-M. When QEMU detects a "virt" machine, some extra data
is generated in memory of the target, and that happens to be placed in
the region that is really for .tbss, but according to the .elf file,
there is a hole there without this patch.
>
> On the other hand, this variation of TLS might be generally useful in
> embedded systems. So if you want to go ahead with your patch I'd like
> to see tls_nobits_occupies_vma set from ${EMBEDDED} rather than a
> target test. This will mean you are probably better off modifying
> tls-app.d to allow both sets of numbers rather than specifying all the
> target triples that have targ_emul=armelf to use tls-app-eabi.d.
> While you're at that, replace the ".word 0x000080bc" and
> similar with ".*".
>
I've updated the patch, please see v2 here:
https://sourceware.org/pipermail/binutils/2026-September/151184.html
Is this what you had in mind or did I miss any of your thoughts?
Kind regards,
Torbjörn
@@ -58,6 +58,7 @@ gld${EMULATION_NAME}_before_parse (void)
#endif /* not TARGET_ */
input_flags.dynamic = ${DYNAMIC_LINK-true};
config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo true ; else echo false ; fi`;
+ config.tls_nobits_occupies_vma = `case ${target} in arm*-*-eabi*) echo true ;; *) echo false ;; esac`;
config.separate_code = `if test "x${SEPARATE_CODE}" = xyes ; then echo true ; else echo false ; fi`;
EOF
if test -n "$COMMONPAGESIZE"; then
@@ -236,6 +236,10 @@ typedef struct
parameter. */
bool has_shared;
+ /* If TRUE, TLS NOBITS sections consume VMA like other allocated
+ sections. */
+ bool tls_nobits_occupies_vma;
+
/* If TRUE, build constructors. */
bool build_constructors;
@@ -5890,8 +5890,11 @@ sort_sections_by_vma (const void *arg1, const void *arg2)
#define IS_TBSS(s) \
((s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == SEC_THREAD_LOCAL)
+#define TBSS_EFFECTIVELY_ZERO(s) \
+ (IS_TBSS (s) && !config.tls_nobits_occupies_vma)
+
#define IGNORE_SECTION(s) \
- ((s->flags & SEC_ALLOC) == 0 || IS_TBSS (s))
+ ((s->flags & SEC_ALLOC) == 0 || TBSS_EFFECTIVELY_ZERO (s))
/* Check to see if any allocated sections overlap with other allocated
sections. This can happen if a linker script specifies the output
@@ -6433,8 +6436,8 @@ lang_size_sections_1
if (bfd_is_abs_section (os->bfd_section) || os->ignored)
break;
- /* .tbss sections effectively have zero size. */
- if (!IS_TBSS (os->bfd_section)
+ /* Hosted .tbss sections effectively have zero size. */
+ if (!TBSS_EFFECTIVELY_ZERO (os->bfd_section)
|| bfd_link_relocatable (&link_info))
dotdelta = TO_ADDR (os->bfd_section->size);
else
@@ -6813,7 +6816,7 @@ lang_size_relro_segment_1 (void)
bfd_vma start, end, bump;
end = start = sec->vma;
- if (!IS_TBSS (sec))
+ if (!TBSS_EFFECTIVELY_ZERO (sec))
end += TO_ADDR (sec->size);
bump = desired_end - end;
/* We'd like to increase START by BUMP, but we must heed
@@ -6936,8 +6939,8 @@ lang_do_assignments_1 (lang_statement_union_type *s,
{
newdot = os->bfd_section->vma;
- /* .tbss sections effectively have zero size. */
- if (!IS_TBSS (os->bfd_section)
+ /* Hosted .tbss sections effectively have zero size. */
+ if (!TBSS_EFFECTIVELY_ZERO (os->bfd_section)
|| bfd_link_relocatable (&link_info))
newdot += TO_ADDR (os->bfd_section->size);
@@ -120,20 +120,25 @@ set tmp {
"arm-call"}
}
append armelftests_common $tmp
-set tmp {
+if {[istarget "arm*-*-eabi*"]} {
+ set tls_app_dump tls-app-eabi.d
+} else {
+ set tls_app_dump tls-app.d
+}
+set tmp [subst -nocommands -nobackslashes {
{"TLS shared library" "-shared -T arm-lib.ld --hash-style=sysv" ""
"" {tls-lib.s}
{{objdump -fdw tls-lib.d} {objdump -Rw tls-lib.r}}
"tls-lib.so"}
{"TLS dynamic application"
"-T arm-dyn.ld --hash-style=sysv tmpdir/tls-lib.so" "" "" {tls-app.s}
- {{objdump -fdw tls-app.d} {objdump -Rw tls-app.r}}
+ {{objdump -fdw $tls_app_dump} {objdump -Rw tls-app.r}}
"tls-app"}
{"TLS gnu shared library got"
"-shared -T arm-dyn.ld --hash-style=sysv" "" "" {tls-gdesc-got.s}
{{objdump "-fDR -j .got" tls-gdesc-got.d}}
"tls-lib2-got.so"}
-}
+}]
if [check_shared_lib_support] { append armelftests_common $tmp }
set tmp {
{"TLS gnu GD to IE relaxation"
@@ -432,6 +437,13 @@ run_dump_test "rel32-reject"
run_dump_test "rel32-reject-pie"
run_dump_test "pie-bind-locally"
+if {[istarget "arm*-*-eabi*"]} {
+ run_dump_test "tls-nobits-vma-static"
+ run_dump_test "tls-nobits-vma-exec"
+ run_dump_test "tls-nobits-vma-pie"
+ run_dump_test "tls-nobits-vma-dynamic"
+}
+
# Exclude non-ARM-EABI targets.
if { [istarget "arm*-*-netbsd*"] } {
new file mode 100644
@@ -0,0 +1,18 @@
+
+.*: file format elf32-.*arm.*
+architecture: arm.*, flags 0x00000112:
+EXEC_P, HAS_SYMS, D_PAGED
+start address 0x00008[0-9a-f]+
+
+Disassembly of section .text:
+
+00008[0-9a-f]+ <foo>:
+ 8[0-9a-f]+: e1a00000 nop @ \(mov r0, r0\)
+ 8[0-9a-f]+: e1a00000 nop @ \(mov r0, r0\)
+ 8[0-9a-f]+: e1a0f00e mov pc, lr
+ 8[0-9a-f]+: 000080c4 .word 0x000080c4
+ 8[0-9a-f]+: 000080bc .word 0x000080bc
+ 8[0-9a-f]+: 000080b4 .word 0x000080b4
+ 8[0-9a-f]+: 00000004 .word 0x00000004
+ 8[0-9a-f]+: 000080cc .word 0x000080cc
+ 8[0-9a-f]+: 00000014 .word 0x00000014
new file mode 100644
@@ -0,0 +1,27 @@
+#source: tls-nobits-vma.s
+#ld: -shared -T tls-nobits-vma.ld
+#readelf: -hSW
+
+ELF Header:
+#...
+ Type: +DYN \(Shared object file\)
+#...
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
+ \[ 1\] .dynsym +DYNSYM +00008000 +[0-9a-f]+ +000010 +10 +A +2 +1 +4
+ \[ 2\] .dynstr +STRTAB +00008010 +[0-9a-f]+ +000001 +00 +A +0 +0 +1
+ \[ 3\] .hash +HASH +00008014 +[0-9a-f]+ +000010 +04 +A +1 +0 +4
+ \[ 4\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
+ \[ 5\] .dynamic +DYNAMIC +00001004 +[0-9a-f]+ +000058 +08 +WA +2 +0 +4
+ \[ 6\] .got.plt +PROGBITS +0000105c +[0-9a-f]+ +00000c +04 +WA +0 +0 +4
+ \[ 7\] .tdata +PROGBITS +00001068 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 8\] .tbss +NOBITS +0000106c +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 9\] .bss +NOBITS +00001070 +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
+ \[10\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[11\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +12 +[0-9]+ +4
+ \[12\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[13\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+Key to Flags:
+#...
new file mode 100644
@@ -0,0 +1,22 @@
+#source: tls-nobits-vma.s
+#ld: -T tls-nobits-vma.ld
+#readelf: -hSW
+
+ELF Header:
+#...
+ Type: +EXEC \(Executable file\)
+#...
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
+ \[ 1\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
+ \[ 2\] .tdata +PROGBITS +00001004 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 3\] .tbss +NOBITS +00001008 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 4\] .bss +NOBITS +0000100c +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
+ \[ 5\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[ 6\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +7 +[0-9]+ +4
+ \[ 7\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[ 8\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+Key to Flags:
+#...
new file mode 100644
@@ -0,0 +1,28 @@
+#source: tls-nobits-vma.s
+#ld: -pie -T tls-nobits-vma.ld
+#readelf: -hSW
+
+ELF Header:
+#...
+ Type: +EXEC \(Executable file\)
+#...
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
+ \[ 1\] .interp +PROGBITS +00008000 +[0-9a-f]+ +000011 +00 +A +0 +0 +1
+ \[ 2\] .dynsym +DYNSYM +00008014 +[0-9a-f]+ +000010 +10 +A +3 +1 +4
+ \[ 3\] .dynstr +STRTAB +00008024 +[0-9a-f]+ +000001 +00 +A +0 +0 +1
+ \[ 4\] .hash +HASH +00008028 +[0-9a-f]+ +000010 +04 +A +2 +0 +4
+ \[ 5\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
+ \[ 6\] .dynamic +DYNAMIC +00001004 +[0-9a-f]+ +000068 +08 +WA +3 +0 +4
+ \[ 7\] .got.plt +PROGBITS +0000106c +[0-9a-f]+ +00000c +04 +WA +0 +0 +4
+ \[ 8\] .tdata +PROGBITS +00001078 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 9\] .tbss +NOBITS +0000107c +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[10\] .bss +NOBITS +00001080 +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
+ \[11\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[12\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +13 +[0-9]+ +4
+ \[13\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[14\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+Key to Flags:
+#...
new file mode 100644
@@ -0,0 +1,22 @@
+#source: tls-nobits-vma.s
+#ld: -static -T tls-nobits-vma.ld
+#readelf: -hSW
+
+ELF Header:
+#...
+ Type: +EXEC \(Executable file\)
+#...
+
+Section Headers:
+ \[Nr\] Name +Type +Addr +Off +Size +ES Flg Lk Inf Al
+ \[ 0\] +NULL +0+ +0+ +0+ +0+ +0 +0 +0
+ \[ 1\] .data +PROGBITS +00001000 +[0-9a-f]+ +000004 +00 +WA +0 +0 +4
+ \[ 2\] .tdata +PROGBITS +00001004 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 3\] .tbss +NOBITS +00001008 +[0-9a-f]+ +000004 +00 WAT +0 +0 +4
+ \[ 4\] .bss +NOBITS +0000100c +[0-9a-f]+ +000008 +00 +WA +0 +0 +4
+ \[ 5\] .ARM.attributes +ARM_ATTRIBUTES +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[ 6\] .symtab +SYMTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +10 +7 +[0-9]+ +4
+ \[ 7\] .strtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+ \[ 8\] .shstrtab +STRTAB +0+ +[0-9a-f]+ +[0-9a-f]+ +00 +0 +0 +1
+Key to Flags:
+#...
new file mode 100644
@@ -0,0 +1,13 @@
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x8000, LENGTH = 0x1000
+ RAM (rw) : ORIGIN = 0x1000, LENGTH = 0x1000
+}
+
+SECTIONS
+{
+ .data : ALIGN(4) { *(.data) } >RAM AT>FLASH
+ .tdata : ALIGN(4) { *(.tdata) } >RAM AT>FLASH
+ .tbss (NOLOAD) : ALIGN(4) { *(.tbss) } >RAM
+ .bss (NOLOAD) : ALIGN(4) { *(.bss) } >RAM
+}
new file mode 100644
@@ -0,0 +1,11 @@
+ .section .data,"aw",%progbits
+ .word 1
+
+ .section .tdata,"awT",%progbits
+ .word 2
+
+ .section .tbss,"awT",%nobits
+ .space 4
+
+ .section .bss,"aw",%nobits
+ .space 8