@@ -422,8 +422,21 @@ pub struct EncodingState<'a> {
422422 /// Maps from original export name to task initialization wrapper function index.
423423 /// Used to wrap exports with __wasm_init_(async_)task calls.
424424 export_task_initialization_wrappers : HashMap < String , u32 > ,
425+
426+ /// The index of the instance of the synthesized module which stores the TLS
427+ /// base pointer in a `global`.
428+ ///
429+ /// This is only used, and only created, when a module imports
430+ /// `__wasm_{get,set}_tls_base` but the program doesn't use cooperative
431+ /// threading. See `materialize_tls_base_import`.
432+ tls_base_instance_index : Option < ( u32 , ValType ) > ,
425433}
426434
435+ /// Name of the export of the synthesized TLS-base module which reads the base.
436+ const TLS_BASE_GET : & str = "get" ;
437+ /// Name of the export of the synthesized TLS-base module which writes the base.
438+ const TLS_BASE_SET : & str = "set" ;
439+
427440impl < ' a > EncodingState < ' a > {
428441 fn encode_core_modules ( & mut self ) {
429442 assert ! ( self . module_index. is_none( ) ) ;
@@ -1991,6 +2004,14 @@ impl<'a> EncodingState<'a> {
19912004 let index = self . component . context_set ( ( * ty) . try_into ( ) ?, * slot) ;
19922005 Ok ( ( ExportKind :: Func , index) )
19932006 }
2007+ Import :: TlsBaseGet { ty } => Ok ( (
2008+ ExportKind :: Func ,
2009+ self . materialize_tls_base_import ( false , ( * ty) . try_into ( ) ?) ,
2010+ ) ) ,
2011+ Import :: TlsBaseSet { ty } => Ok ( (
2012+ ExportKind :: Func ,
2013+ self . materialize_tls_base_import ( true , ( * ty) . try_into ( ) ?) ,
2014+ ) ) ,
19942015 Import :: ExportedTaskCancel => {
19952016 let index = self . component . task_cancel ( ) ;
19962017 Ok ( ( ExportKind :: Func , index) )
@@ -2037,6 +2058,93 @@ impl<'a> EncodingState<'a> {
20372058 }
20382059 }
20392060
2061+ /// Helper to satisfy `__wasm_{get,set}_tls_base` imports.
2062+ ///
2063+ /// For more information on this see WebAssembly/wasi-libc#857
2064+ fn materialize_tls_base_import ( & mut self , set : bool , ty : ValType ) -> u32 {
2065+ if self . info . uses_cooperative_threading ( ) {
2066+ return if set {
2067+ self . component . context_set ( ty, 1 )
2068+ } else {
2069+ self . component . context_get ( ty, 1 )
2070+ } ;
2071+ }
2072+
2073+ let instance = match self . tls_base_instance_index {
2074+ Some ( ( index, prev_ty) ) => {
2075+ assert_eq ! ( prev_ty, ty, "conflicting TLS base pointer types" ) ;
2076+ index
2077+ }
2078+ None => {
2079+ let index = self . encode_tls_base_module ( ty) ;
2080+ self . tls_base_instance_index = Some ( ( index, ty) ) ;
2081+ index
2082+ }
2083+ } ;
2084+ let name = if set { TLS_BASE_SET } else { TLS_BASE_GET } ;
2085+ self . core_alias_export (
2086+ Some ( & format ! ( "tls-base-{name}" ) ) ,
2087+ instance,
2088+ name,
2089+ ExportKind :: Func ,
2090+ )
2091+ }
2092+
2093+ /// Synthesizes and instantiates a module which stores the TLS base pointer
2094+ /// in a mutable `global`, exporting accessors for it.
2095+ fn encode_tls_base_module ( & mut self , ty : ValType ) -> u32 {
2096+ let mut types = TypeSection :: new ( ) ;
2097+ types. ty ( ) . function ( [ ] , [ ty] ) ;
2098+ types. ty ( ) . function ( [ ty] , [ ] ) ;
2099+
2100+ let mut globals = GlobalSection :: new ( ) ;
2101+ globals. global (
2102+ wasm_encoder:: GlobalType {
2103+ val_type : ty,
2104+ mutable : true ,
2105+ shared : false ,
2106+ } ,
2107+ & match ty {
2108+ ValType :: I64 => ConstExpr :: i64_const ( 0 ) ,
2109+ ValType :: I32 => ConstExpr :: i32_const ( 0 ) ,
2110+ _ => unreachable ! ( ) ,
2111+ } ,
2112+ ) ;
2113+
2114+ let mut functions = FunctionSection :: new ( ) ;
2115+ let mut code = CodeSection :: new ( ) ;
2116+
2117+ functions. function ( 0 ) ;
2118+ let mut get = wasm_encoder:: Function :: new ( [ ] ) ;
2119+ get. instruction ( & Instruction :: GlobalGet ( 0 ) ) ;
2120+ get. instruction ( & Instruction :: End ) ;
2121+ code. function ( & get) ;
2122+
2123+ functions. function ( 1 ) ;
2124+ let mut set = wasm_encoder:: Function :: new ( [ ] ) ;
2125+ set. instruction ( & Instruction :: LocalGet ( 0 ) ) ;
2126+ set. instruction ( & Instruction :: GlobalSet ( 0 ) ) ;
2127+ set. instruction ( & Instruction :: End ) ;
2128+ code. function ( & set) ;
2129+
2130+ let mut exports = ExportSection :: new ( ) ;
2131+ exports. export ( TLS_BASE_GET , ExportKind :: Func , 0 ) ;
2132+ exports. export ( TLS_BASE_SET , ExportKind :: Func , 1 ) ;
2133+
2134+ let mut module = Module :: new ( ) ;
2135+ module. section ( & types) ;
2136+ module. section ( & functions) ;
2137+ module. section ( & globals) ;
2138+ module. section ( & exports) ;
2139+ module. section ( & code) ;
2140+
2141+ let module_index = self
2142+ . component
2143+ . core_module ( Some ( "wit-component:tls-base" ) , & module) ;
2144+ self . component
2145+ . core_instantiate ( Some ( "wit-component:tls-base" ) , module_index, [ ] )
2146+ }
2147+
20402148 /// Helper for `materialize_import` above for materializing functions that
20412149 /// are part of the "shim module" generated.
20422150 fn materialize_shim_import ( & mut self , shims : & Shims < ' _ > , kind : & ShimKind ) -> ( ExportKind , u32 ) {
@@ -2686,6 +2794,8 @@ impl<'a> Shims<'a> {
26862794 | Import :: WaitableJoin
26872795 | Import :: ContextGet { .. }
26882796 | Import :: ContextSet { .. }
2797+ | Import :: TlsBaseGet { .. }
2798+ | Import :: TlsBaseSet { .. }
26892799 | Import :: ThreadIndex
26902800 | Import :: ThreadResumeLater
26912801 | Import :: ThreadSuspend { .. }
@@ -3411,6 +3521,7 @@ impl ComponentEncoder {
34113521 aliased_core_items : Default :: default ( ) ,
34123522 info : & world,
34133523 export_task_initialization_wrappers : HashMap :: new ( ) ,
3524+ tls_base_instance_index : None ,
34143525 } ;
34153526 state. encode_imports ( & self . import_name_map ) ?;
34163527 state. encode_core_modules ( ) ;
0 commit comments