diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c --- a/libexec/rtld-elf/aarch64/reloc.c +++ b/libexec/rtld-elf/aarch64/reloc.c @@ -521,7 +521,7 @@ * use. */ tls_static_space = tls_last_offset + tls_last_size + - RTLD_STATIC_TLS_EXTRA; + ld_static_tls_extra; _tcb_set(allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); } diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c --- a/libexec/rtld-elf/amd64/reloc.c +++ b/libexec/rtld-elf/amd64/reloc.c @@ -527,7 +527,7 @@ * offset allocated so far and adding a bit for dynamic * modules to use. */ - tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + tls_static_space = tls_last_offset + ld_static_tls_extra; addr = allocate_tls(objs, 0, TLS_TCB_SIZE, TLS_TCB_ALIGN); diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -454,7 +454,8 @@ * use. */ - tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + tls_static_space = tls_last_offset + tls_last_size + + ld_static_tls_extra; _tcb_set(allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); } diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -510,7 +510,7 @@ * offset allocated so far and adding a bit for dynamic modules to * use. */ - tls_static_space = tls_last_offset + RTLD_STATIC_TLS_EXTRA; + tls_static_space = tls_last_offset + ld_static_tls_extra; tls = allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); _tcb_set(tls); } diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -817,7 +817,8 @@ * use. */ - tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + tls_static_space = tls_last_offset + tls_last_size + + ld_static_tls_extra; _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); } diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -714,7 +714,8 @@ * use. */ - tls_static_space = tls_last_offset + tls_last_size + RTLD_STATIC_TLS_EXTRA; + tls_static_space = tls_last_offset + tls_last_size + + ld_static_tls_extra; _tcb_set(allocate_tls(list, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); } diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c --- a/libexec/rtld-elf/riscv/reloc.c +++ b/libexec/rtld-elf/riscv/reloc.c @@ -392,7 +392,7 @@ * use. */ tls_static_space = tls_last_offset + tls_last_size + - RTLD_STATIC_TLS_EXTRA; + ld_static_tls_extra; _tcb_set(allocate_tls(objs, NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN)); } diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -50,6 +50,7 @@ extern size_t tls_static_space; extern Elf_Addr tls_dtv_generation; extern int tls_max_index; +extern size_t ld_optional_static_tls; extern int npagesizes; extern size_t *pagesizes; diff --git a/libexec/rtld-elf/rtld.1 b/libexec/rtld-elf/rtld.1 --- a/libexec/rtld-elf/rtld.1 +++ b/libexec/rtld-elf/rtld.1 @@ -26,7 +26,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd November 10, 2022 +.Dd October 29, 2023 .Dt RTLD 1 .Os .Sh NAME @@ -320,6 +320,12 @@ .Nm to dump content of the aux vector to standard output, before passing control to any user code. +.It Ev LD_OPTIONAL_STATIC_TLS +If the variable is specified and has a numeric value, +.Nm +will set the size of the optional static TLS space to the specified number +of bytes. The optional static TLS space is used when loading objects with +dlopen. The minimum value that can be specified is \'128\'. .El .Sh DIRECT EXECUTION MODE .Nm diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -225,6 +225,8 @@ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ static unsigned int obj_loads; /* Number of loads of objects (gen count) */ +size_t ld_static_tls_extra = /* Optional static TLS space (bytes) */ + RTLD_STATIC_TLS_EXTRA; static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -365,6 +367,7 @@ LD_TRACE_LOADED_OBJECTS_FMT2, LD_TRACE_LOADED_OBJECTS_ALL, LD_SHOW_AUXV, + LD_OPTIONAL_STATIC_TLS, }; struct ld_env_var_desc { @@ -398,6 +401,7 @@ LD_ENV_DESC(TRACE_LOADED_OBJECTS_FMT2, false), LD_ENV_DESC(TRACE_LOADED_OBJECTS_ALL, false), LD_ENV_DESC(SHOW_AUXV, false), + LD_ENV_DESC(OPTIONAL_STATIC_TLS, false), }; static const char * @@ -515,7 +519,7 @@ struct stat st; Elf_Addr *argcp; char **argv, **env, **envp, *kexecpath; - const char *argv0, *binpath, *library_path_rpath; + const char *argv0, *binpath, *library_path_rpath, *static_tls_extra; struct ld_env_var_desc *lvd; caddr_t imgentry; char buf[MAXPATHLEN]; @@ -738,9 +742,16 @@ else ld_library_path_rpath = false; } + static_tls_extra = ld_get_env_var(LD_OPTIONAL_STATIC_TLS); + if (static_tls_extra != NULL && static_tls_extra[0] != '\0') { + sz = parse_integer(static_tls_extra); + if (sz >= RTLD_STATIC_TLS_EXTRA && sz <= SIZE_T_MAX) + ld_static_tls_extra = sz; + } dangerous_ld_env = libmap_disable || libmap_override != NULL || ld_library_path != NULL || ld_preload != NULL || - ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak; + ld_elf_hints_path != NULL || ld_loadfltr || !ld_dynamic_weak || + ld_static_tls_extra; ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS); ld_utrace = ld_get_env_var(LD_UTRACE); @@ -6105,13 +6116,15 @@ "Env prefix %s\n" "Default hint file %s\n" "Hint file %s\n" - "libmap file %s\n", + "libmap file %s\n" + "Optional static TLS size %zd bytes\n", machine, __FreeBSD_version, ld_standard_library_path, gethints(false), ld_env_prefix, ld_elf_hints_default, ld_elf_hints_path, - ld_path_libmap_conf); + ld_path_libmap_conf, + ld_static_tls_extra); _exit(0); } else { _rtld_error("Invalid argument: '%s'", arg);