Repository navigation
tools/nxflat: Place the sections of C++ modules and refuse what NXFLAT cannot run. - #20805
Merged
Merged
Conversation
An NXFLAT module starts at its main() and has no start-up code, so nothing runs its .init_array, .fini_array or .preinit_array. The NXFLAT linker scripts do not place these sections either. ld leaves them at address zero, on top of .data, and ldnxflat copied them there. hello++3 of apps/examples/nxflat is an example. Its .init_array is at D-Space address 0, and its .bss starts at 4, inside .data. The constructor pointer overwrites the first word of .data, the static variables share their addresses with initialized data, and the constructor never runs. Refuse such a module and name the section. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
ld -r keeps each member of a section group as a section of its own, and the NXFLAT linker scripts do not place it. It stays at address zero, on top of .text or .data, and the sections that the script places after it move. C++ puts inline functions and template instances in COMDAT groups, so many C++ modules have such sections. For example, the emutls control objects of a static thread_local member of a class template are in two groups. ld put them at D-Space address 0 and .bss at 0x10, so all three overlapped .data. ldnxflat copied one over the other with no message. exec() then failed with ENOENT: the loader read the name of the first import as "flat_abi_v2". Place the sections in ldnxflat: in the order of the section headers, each at its alignment, the data of D-Space before its .bss. A relocatable ELF object gives symbols and relocations as offsets in their section, so nothing else changes. The modules of apps/examples/nxflat convert to the same bytes as before. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
A toolchain with native TLS, such as Arm GNU 15.3 for arm-none-eabi, puts __thread variables in .tdata and .tbss and reaches them with __tls_get_addr() and R_ARM_TLS_GD32. NXFLAT has no thread pointer and no TLS relocations, so such a module cannot work. ldnxflat refused it only at the first TLS relocation, with "arm relocation 104 at I-Space 00000118 is not handled", which does not say why. Refuse a module with a TLS section and say what to do: build it with a toolchain that emulates TLS. There, __thread compiles into calls to __emutls_get_address(), which the module imports like any other function. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
When ldnxflat failed, the report showed the first line of its output that holds "error". ldnxflat does not write that word, so the reason column stayed empty. Show the first line of the output instead. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
…FLAT. Add two limitations to the NXFLAT page: a module can use __thread and thread_local variables only with emulated TLS, and nothing runs the static constructors and destructors of a module. ldnxflat refuses a module with native TLS sections or with an .init_array or .fini_array. Also say that ldnxflat places the sections itself, so a section that the linker script does not name does not overlap another one. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
xiaoxiang781216
approved these changes
Oct 19, 2026
cederom
approved these changes
Oct 19, 2026
hartmannathan
approved these changes
Oct 19, 2026
|
acassis
approved these changes
Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ldnxflat converted some modules into a broken image with no message. The NXFLAT linker scripts give an address only to the sections that they name.
ld -rkeeps each member of a section group (a C++ COMDAT group) as a section of its own, and it leaves.init_array,.fini_array,.tdataand.tbssunplaced too. Such a section stays at address zero, on top of.textor.data, and moves the sections that follow it. ldnxflat copied all of them into the image.Examples: a C++ module with the static
thread_localmember of a class template has its emutls control objects in two COMDAT groups. ld put both at D-Space 0 and.bssat 0x10, inside.data, andexec()of the module failed.hello++3of apps/examples/nxflat has its.init_arrayat D-Space 0 and its.bssat 4, and nothing runs its constructor.This PR:
.init_array,.fini_arrayor.preinit_array. Nothing runs these arrays in an NXFLAT module..bss, and do not use the addresses of the linker script. Group members then get their own place..tdata,.tbss) with a message that says to use a toolchain that emulates TLS. Before, the module failed at the first TLS relocation with "arm relocation 104 ... is not handled".With a toolchain that emulates TLS (arm-none-eabi 13.2, as in CI),
__threadandthread_localalready work in an NXFLAT module: the module imports__emutls_get_address()like any other function, and its control objects and templates are relocated correctly. The new tests are in apache/nuttx-apps#3880.Impact
Host tool and documentation only. All modules of apps/examples/nxflat that converted before convert to the same bytes.
hello++3(not built by default) is now refused instead of converted wrong.Testing
lm3s6965-ek:qemu-nxflat with arm-none-eabi 13.2,
CONFIG_HAVE_CXX=y, underqemu-system-arm -M lm3s6965evb, with the tests of apache/nuttx-apps#3880:exec()fails, ENOENTexec()fails, ENOENTThe checks of the second thread pass only when the base code keeps a copy of each
__threadvariable per thread. libgcc's emutls keeps one copy for all threads; #20723 adds a per-thread copy to libc. With this PR and #20723, both modules pass with both linker scripts (gnu-nxflat-pcrel.ldandgnu-nxflat-gotoff.ld).tools/nxflat/testsuite.sh(gotoff): all modules convert as before;hello++3now fails with ".init_array holds static constructors or destructors, which an NXFLAT module cannot run". With arm-none-eabi 15.3 (native TLS), tls fails with ".tbss holds native TLS, which an NXFLAT module cannot use; build it with a toolchain that emulates TLS".tools/checkpatch.sh -c -u -m -gpasses.