@@ -49,6 +49,8 @@ pub struct X86_64CodeGen {
4949 pub ( super ) unique_label_counter : u32 ,
5050 /// External symbols (need GOT access on macOS)
5151 pub ( super ) extern_symbols : HashSet < String > ,
52+ /// Thread-local storage symbols (need TLS access via FS segment)
53+ pub ( super ) tls_symbols : HashSet < String > ,
5254 /// Position-independent code mode (for shared libraries)
5355 pic_mode : bool ,
5456 /// Long double constants to emit (label_bits -> value_bits)
@@ -70,6 +72,7 @@ impl X86_64CodeGen {
7072 num_fixed_fp_params : 0 ,
7173 unique_label_counter : 0 ,
7274 extern_symbols : HashSet :: new ( ) ,
75+ tls_symbols : HashSet :: new ( ) ,
7376 pic_mode : false ,
7477 ld_constants : HashMap :: new ( ) ,
7578 double_constants : HashMap :: new ( ) ,
@@ -110,7 +113,12 @@ impl X86_64CodeGen {
110113 } else {
111114 Symbol :: global ( name. clone ( ) )
112115 } ;
113- GpOperand :: Mem ( MemAddr :: RipRelative ( symbol) )
116+ // Use TLS addressing for thread-local variables (Linux only)
117+ if self . tls_symbols . contains ( name) && self . base . target . os == Os :: Linux {
118+ GpOperand :: Mem ( MemAddr :: TlsIE ( symbol) )
119+ } else {
120+ GpOperand :: Mem ( MemAddr :: RipRelative ( symbol) )
121+ }
114122 }
115123 }
116124 }
@@ -1448,8 +1456,14 @@ impl X86_64CodeGen {
14481456 }
14491457 }
14501458 Loc :: Global ( name) => {
1451- // LIR: RIP-relative memory-to-register move
1459+ // LIR: memory-to-register move
14521460 // Use local symbol for labels starting with '.' (e.g., .LC0 for string constants)
1461+ let symbol = if name. starts_with ( '.' ) {
1462+ Symbol :: local ( name. clone ( ) )
1463+ } else {
1464+ Symbol :: global ( name. clone ( ) )
1465+ } ;
1466+
14531467 if self . needs_got_access ( & name) {
14541468 // External symbols on macOS: load address from GOT, then load value
14551469 // Use R11 as temp if dst is R11, otherwise use dst
@@ -1467,12 +1481,15 @@ impl X86_64CodeGen {
14671481 } ) ,
14681482 dst : GpOperand :: Reg ( dst) ,
14691483 } ) ;
1484+ } else if self . tls_symbols . contains ( & name) && self . base . target . os == Os :: Linux {
1485+ // Thread-local storage: use FS segment (initial-exec model)
1486+ self . push_lir ( X86Inst :: Mov {
1487+ size : op_size,
1488+ src : GpOperand :: Mem ( MemAddr :: TlsIE ( symbol) ) ,
1489+ dst : GpOperand :: Reg ( dst) ,
1490+ } ) ;
14701491 } else {
1471- let symbol = if name. starts_with ( '.' ) {
1472- Symbol :: local ( name. clone ( ) )
1473- } else {
1474- Symbol :: global ( name. clone ( ) )
1475- } ;
1492+ // Regular RIP-relative access
14761493 self . push_lir ( X86Inst :: Mov {
14771494 size : op_size,
14781495 src : GpOperand :: Mem ( MemAddr :: RipRelative ( symbol) ) ,
@@ -1842,21 +1859,28 @@ impl X86_64CodeGen {
18421859 } else {
18431860 Symbol :: global ( name. clone ( ) )
18441861 } ;
1862+ // Choose addressing mode: TLS or RIP-relative
1863+ let mem_addr =
1864+ if self . tls_symbols . contains ( & name) && self . base . target . os == Os :: Linux {
1865+ MemAddr :: TlsIE ( symbol)
1866+ } else {
1867+ MemAddr :: RipRelative ( symbol)
1868+ } ;
18451869 if mem_size <= 16 {
18461870 // LIR: sign/zero extending load from global
18471871 let src_size = OperandSize :: from_bits ( mem_size) ;
18481872 if is_unsigned {
18491873 self . push_lir ( X86Inst :: Movzx {
18501874 src_size,
18511875 dst_size : OperandSize :: B32 ,
1852- src : GpOperand :: Mem ( MemAddr :: RipRelative ( symbol . clone ( ) ) ) ,
1876+ src : GpOperand :: Mem ( mem_addr . clone ( ) ) ,
18531877 dst : dst_reg,
18541878 } ) ;
18551879 } else {
18561880 self . push_lir ( X86Inst :: Movsx {
18571881 src_size,
18581882 dst_size : OperandSize :: B32 ,
1859- src : GpOperand :: Mem ( MemAddr :: RipRelative ( symbol . clone ( ) ) ) ,
1883+ src : GpOperand :: Mem ( mem_addr . clone ( ) ) ,
18601884 dst : dst_reg,
18611885 } ) ;
18621886 }
@@ -1865,7 +1889,7 @@ impl X86_64CodeGen {
18651889 let op_size = OperandSize :: from_bits ( reg_size) ;
18661890 self . push_lir ( X86Inst :: Mov {
18671891 size : op_size,
1868- src : GpOperand :: Mem ( MemAddr :: RipRelative ( symbol ) ) ,
1892+ src : GpOperand :: Mem ( mem_addr ) ,
18691893 dst : GpOperand :: Reg ( dst_reg) ,
18701894 } ) ;
18711895 }
@@ -2022,6 +2046,12 @@ impl X86_64CodeGen {
20222046 // Use local symbol for labels starting with '.' (e.g., .LC0 for string constants)
20232047 let is_local_label = name. starts_with ( '.' ) ;
20242048 let op_size = OperandSize :: from_bits ( mem_size) ;
2049+ let symbol = if is_local_label {
2050+ Symbol :: local ( name. clone ( ) )
2051+ } else {
2052+ Symbol :: global ( name. clone ( ) )
2053+ } ;
2054+
20252055 if self . needs_got_access ( & name) {
20262056 // External symbols on macOS: load address from GOT, then store
20272057 self . push_lir ( X86Inst :: Mov {
@@ -2037,12 +2067,14 @@ impl X86_64CodeGen {
20372067 offset : insn. offset as i32 ,
20382068 } ) ,
20392069 } ) ;
2070+ } else if self . tls_symbols . contains ( & name) && self . base . target . os == Os :: Linux {
2071+ // Thread-local storage: use FS segment (initial-exec model)
2072+ self . push_lir ( X86Inst :: Mov {
2073+ size : op_size,
2074+ src : GpOperand :: Reg ( value_reg) ,
2075+ dst : GpOperand :: Mem ( MemAddr :: TlsIE ( symbol) ) ,
2076+ } ) ;
20402077 } else {
2041- let symbol = if is_local_label {
2042- Symbol :: local ( name. clone ( ) )
2043- } else {
2044- Symbol :: global ( name. clone ( ) )
2045- } ;
20462078 // LIR: store to global via RIP-relative
20472079 self . push_lir ( X86Inst :: Mov {
20482080 size : op_size,
@@ -3578,6 +3610,14 @@ impl CodeGenerator for X86_64CodeGen {
35783610 self . base . emit_debug = module. debug ;
35793611 self . extern_symbols = module. extern_symbols . clone ( ) ;
35803612
3613+ // Collect thread-local storage symbols
3614+ self . tls_symbols = module
3615+ . globals
3616+ . iter ( )
3617+ . filter ( |g| g. is_thread_local )
3618+ . map ( |g| g. name . clone ( ) )
3619+ . collect ( ) ;
3620+
35813621 // Emit file header
35823622 self . emit_header ( ) ;
35833623
0 commit comments