git: 0b56acfc498e - stable/14 - rtld: introduce STATIC_TLS_EXTRA

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 20 Apr 2024 13:53:39 UTC
The branch stable/14 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=0b56acfc498ed2cc325f6b8debfc7fdc3b03d676

commit 0b56acfc498ed2cc325f6b8debfc7fdc3b03d676
Author:     Stephen J. Kiernan <stevek@FreeBSD.org>
AuthorDate: 2023-10-29 21:13:10 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-04-20 13:52:16 +0000

    rtld: introduce STATIC_TLS_EXTRA
    
    (cherry picked from commit 95335dd3c19e0ade161bb4dc8462fc3d045ce4f8)
---
 libexec/rtld-elf/aarch64/reloc.c   |  2 +-
 libexec/rtld-elf/amd64/reloc.c     |  2 +-
 libexec/rtld-elf/arm/reloc.c       |  3 ++-
 libexec/rtld-elf/i386/reloc.c      |  2 +-
 libexec/rtld-elf/powerpc/reloc.c   |  3 ++-
 libexec/rtld-elf/powerpc64/reloc.c |  3 ++-
 libexec/rtld-elf/riscv/reloc.c     |  2 +-
 libexec/rtld-elf/rtld.1            |  8 +++++++-
 libexec/rtld-elf/rtld.c            | 21 +++++++++++++++++----
 libexec/rtld-elf/rtld.h            |  1 +
 10 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c
index c8f09d797215..907377f2619a 100644
--- a/libexec/rtld-elf/aarch64/reloc.c
+++ b/libexec/rtld-elf/aarch64/reloc.c
@@ -521,7 +521,7 @@ allocate_initial_tls(Obj_Entry *objs)
 	* 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
index ce74c54cc5c3..9c5887def356 100644
--- a/libexec/rtld-elf/amd64/reloc.c
+++ b/libexec/rtld-elf/amd64/reloc.c
@@ -527,7 +527,7 @@ allocate_initial_tls(Obj_Entry *objs)
 	 * 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
index b2fb3fdad2c7..c3e95940be74 100644
--- a/libexec/rtld-elf/arm/reloc.c
+++ b/libexec/rtld-elf/arm/reloc.c
@@ -454,7 +454,8 @@ allocate_initial_tls(Obj_Entry *objs)
 	* 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
index 8e8966926839..04a8354343bc 100644
--- a/libexec/rtld-elf/i386/reloc.c
+++ b/libexec/rtld-elf/i386/reloc.c
@@ -510,7 +510,7 @@ allocate_initial_tls(Obj_Entry *objs)
      * 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
index 8254f21a3ce6..73a1c89991e2 100644
--- a/libexec/rtld-elf/powerpc/reloc.c
+++ b/libexec/rtld-elf/powerpc/reloc.c
@@ -817,7 +817,8 @@ allocate_initial_tls(Obj_Entry *list)
 	* 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
index 5bfb05116315..70928829aeda 100644
--- a/libexec/rtld-elf/powerpc64/reloc.c
+++ b/libexec/rtld-elf/powerpc64/reloc.c
@@ -714,7 +714,8 @@ allocate_initial_tls(Obj_Entry *list)
 	* 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
index 5ed516bc4337..d806e1ec3d63 100644
--- a/libexec/rtld-elf/riscv/reloc.c
+++ b/libexec/rtld-elf/riscv/reloc.c
@@ -392,7 +392,7 @@ allocate_initial_tls(Obj_Entry *objs)
 	 * 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.1 b/libexec/rtld-elf/rtld.1
index 807ecb31ad7c..4d97159b0aaf 100644
--- 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 @@ If set, causes
 .Nm
 to dump content of the aux vector to standard output, before passing
 control to any user code.
+.It Ev LD_STATIC_TLS_EXTRA
+If the variable is specified and has a numeric value,
+.Nm
+will set the size of the static TLS extra space to the specified number
+of bytes. The static TLS extra 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
index 07068dff0b62..d5e702652058 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -225,6 +225,8 @@ static Obj_Entry *obj_main;	/* The main program shared object */
 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 =	/* Static TLS extra space (bytes) */
+  RTLD_STATIC_TLS_EXTRA;
 
 static Objlist list_global =	/* Objects dlopened with RTLD_GLOBAL */
   STAILQ_HEAD_INITIALIZER(list_global);
@@ -365,6 +367,7 @@ enum {
 	LD_TRACE_LOADED_OBJECTS_FMT2,
 	LD_TRACE_LOADED_OBJECTS_ALL,
 	LD_SHOW_AUXV,
+	LD_STATIC_TLS_EXTRA,
 };
 
 struct ld_env_var_desc {
@@ -398,6 +401,7 @@ static struct ld_env_var_desc ld_env_vars[] = {
 	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(STATIC_TLS_EXTRA, false),
 };
 
 static const char *
@@ -515,7 +519,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
     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 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 	    else
 		    ld_library_path_rpath = false;
     }
+    static_tls_extra = ld_get_env_var(LD_STATIC_TLS_EXTRA);
+    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 ||
+	static_tls_extra != NULL;
     ld_tracing = ld_get_env_var(LD_TRACE_LOADED_OBJECTS);
     ld_utrace = ld_get_env_var(LD_UTRACE);
 
@@ -6165,13 +6176,15 @@ parse_args(char* argv[], int argc, bool *use_pathp, int *fdp,
 				    "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);
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index c9e0d4ab0525..6311b3e6cc7f 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -50,6 +50,7 @@ extern size_t tls_last_size;
 extern size_t tls_static_space;
 extern Elf_Addr tls_dtv_generation;
 extern int tls_max_index;
+extern size_t ld_static_tls_extra;
 
 extern int npagesizes;
 extern size_t *pagesizes;