casaroli opened a new pull request, #3882:
URL: https://github.com/apache/nuttx-apps/pull/3882

   ## Summary
   
   A toolchain without native TLS (for example the Arm GNU toolchain for 
aarch64-none-elf, or arm-none-eabi 13 as in CI) compiles a `__thread` variable 
into calls to `__emutls_get_address()`. In a flat or protected build, 
`Application.mk` and `Library.mk` link libgcc into each loadable module. The 
module refers to `__emutls_get_address()`, so the linker puts `emutls.o` of 
libgcc into the module. That copy is built with the single thread model: all 
threads of the module share one instance of each `__thread` variable. The 
loader never binds the module to the per-thread version of libc.
   
   This PR links such a module with a copy of the compiler runtime in which 
`__emutls_get_address()` and `__emutls_register_common()` are local symbols 
(`objcopy -L`). The linker does not take them, the module keeps them undefined, 
and the loader binds them to libc through the system symbol table. The module 
still takes all the other helpers (`__aeabi_ldivmod`, `__floatditf`, ...) from 
the runtime. The build makes the copy once, in `staging/module/`, with a 
temporary file and a rename, so parallel module links can share it. `make 
clean` removes it.
   
   A library order or a linker option cannot do this. The same object needs 
both `emutls.o` and the other helpers. `--just-symbols` makes the symbol 
absolute, `/DISCARD/` gives "defined in discarded section", `--wrap` renames 
the reference, and ld.lld takes archive members in any order.
   
   depends-on: apache/nuttx/pull/20723 (it exports the per-thread 
`__emutls_get_address()` of libc in libc.csv). The CMake build links modules in 
nuttx `cmake/nuttx_add_application.cmake`; apache/nuttx#20812 does the same 
change there.
   
   ## Impact
   
   - Loadable modules and shared libraries of a flat or protected build that 
use `__thread`: each thread now has its own copy. Without the libc export, the 
module does not load (`Exported symbol "__emutls_get_address" not found`) 
instead of sharing one copy between the threads.
   - Modules without `__thread` variables: no change (`bin/hello` is 
byte-identical).
   - Kernel build programs: no change. They link libc, which comes before 
libgcc.
   - Toolchains with native TLS or a runtime without emutls: the copy is the 
same as the runtime.
   - One copy of the runtime in `apps/staging/module/` when the build has a 
module.
   
   ## Testing
   
   `qemu-armv8a:nsh` (flat, Arm GNU 14.2 aarch64-none-elf, QEMU HVF) with 
`CONFIG_ELF`, `CONFIG_EXECFUNCS_SYSTEM_SYMTAB`, `CONFIG_LIBC_DLFCN` and 
`CONFIG_TLS_NELEM=4`, nuttx with apache/nuttx#20723 and apache/nuttx#20807. The 
same results with `CONFIG_TLS_NELEM=0`. The test programs are built with 
`MODULE = m` by `Application.mk` and loaded from a 9p share. `tlsdl` loads 
`libtlsso.so`, made by `Library.mk`, with `dlopen()`.
   
   | Module | master | this PR | this PR, no emutls export |
   |---|---|---|---|
   | tlsgroup (2 threads, run twice) | FAIL (one address for all threads) | 
PASS | `Exported symbol "__emutls_get_address" not found` |
   | tls4 (4 threads) | FAIL | PASS | not found |
   | tlsmany (12 variables) | FAIL | PASS | not found |
   | uctls (ucontext) | PASS | PASS | not found |
   | tlscxx (C++ `thread_local`) | FAIL | PASS | not found |
   | tlsdl + libtlsso.so | FAIL | PASS | `dlopen()` fails, not found |
   | hello | PASS | PASS (same file) | PASS |
   
   `nm` of a module:
   
   ```
   master:   00000000000001c0 T __emutls_get_address
             0000000000000280 T __emutls_register_common
             U abort  U malloc  U memcpy  U memset ...
   this PR:  U __emutls_get_address
   ```
   
   `mps2-an500:nsh` (flat, arm-none-eabi 13.2 as in CI, QEMU TCG), modules 
loaded from a semihosting hostfs, same tests without uctls: on master no module 
with `__thread` loads, because `emutls.o` of libgcc is not built with 
`-mlong-calls` and calls `malloc()` in the firmware with a branch that cannot 
reach it (`JUMP24 relocation out of range`). With this PR tlsgroup, tls4, 
tlsmany, tlsdl + libtlsso.so and tlscxx PASS, and hello runs as before.
   
   `qemu-armv8a:knsh` (kernel build, export and import): the 11 programs built 
with and without this PR are byte-identical, except the build time string in 
`init` and `sh`; no runtime copy is made.
   
   The uctls test needs `getcontext()`, `makecontext()` and `swapcontext()` in 
libc.csv; the test tree added them locally.
   
   `tools/checkpatch.sh -c -u -m -g` passes.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to