Skip to content

Commit 220f130

Browse files
jgowdyamusman
andcommitted
cmd/link,cmd/compile: add -tls flag for TLS model control
Add -tls flag to control Thread Local Storage model selection with options: auto, LE (Local Exec), IE (Initial Exec), GD (General Dynamic). Default behavior selects GD for c-shared/c-archive builds on Unix platforms to enable dlopen() compatibility with non-glibc systems. Validates TLS model selection to prevent invalid combinations such as LE with shared libraries. Updates all architectures (x86, ARM64, ARM, PowerPC64, s390x, RISC-V, LoongArch64, MIPS) to use centralized TLS model selection logic through ShouldUseTLSGD() and ShouldUseTLSLE() helper functions. Also fixes missing variable declaration in runtime/os_linux.go that was causing build failures. Fixes #13492 Co-Authored-By: Alexander Musman <[email protected]>
1 parent f42e695 commit 220f130

File tree

16 files changed

+205
-22
lines changed

16 files changed

+205
-22
lines changed

src/cmd/compile/internal/base/flag.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ type CmdFlags struct {
119119
Race bool "help:\"enable race detector\""
120120
Shared *bool "help:\"generate code that can be linked into a shared library\"" // &Ctxt.Flag_shared, set below
121121
SmallFrames bool "help:\"reduce the size limit for stack allocated objects\"" // small stacks, to diagnose GC latency; see golang.org/issue/27732
122+
TLS string "help:\"set TLS model (auto, LE, IE, GD)\""
122123
Spectre string "help:\"enable spectre mitigations in `list` (all, index, ret)\""
123124
Std bool "help:\"compiling standard library\""
124125
SymABIs string "help:\"read symbol ABIs from `file`\""
@@ -292,6 +293,11 @@ func ParseFlags() {
292293
log.Fatalf("%s/%s does not support -shared", buildcfg.GOOS, buildcfg.GOARCH)
293294
}
294295
parseSpectre(Flag.Spectre) // left as string for RecordFlags
296+
297+
// Parse TLS model before setting other flags that depend on it
298+
if err := parseTLSModel(Flag.TLS); err != nil {
299+
log.Fatalf("%v", err)
300+
}
295301

296302
Ctxt.Flag_shared = Ctxt.Flag_dynlink || Ctxt.Flag_shared
297303
Ctxt.Flag_optimize = Flag.N == 0
@@ -568,6 +574,27 @@ func readEmbedCfg(file string) {
568574
}
569575
}
570576

577+
// parseTLSModel parses the TLS model from the string s.
578+
func parseTLSModel(s string) error {
579+
if s == "" {
580+
s = "auto" // Default to auto
581+
}
582+
583+
switch s {
584+
case "auto":
585+
Ctxt.TLSModel = obj.TLSModelAuto
586+
case "LE":
587+
Ctxt.TLSModel = obj.TLSModelLE
588+
case "IE":
589+
Ctxt.TLSModel = obj.TLSModelIE
590+
case "GD":
591+
Ctxt.TLSModel = obj.TLSModelGD
592+
default:
593+
return fmt.Errorf("invalid TLS model %q; valid values are auto, LE, IE, GD", s)
594+
}
595+
return nil
596+
}
597+
571598
// parseSpectre parses the spectre configuration from the string s.
572599
func parseSpectre(s string) {
573600
for _, f := range strings.Split(s, ",") {

src/cmd/internal/obj/arm/asm5.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ func (c *ctxt5) aclass(a *obj.Addr) int {
871871

872872
c.instoffset = 0 // s.b. unused but just in case
873873
if a.Sym.Type == objabi.STLSBSS {
874-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
874+
if c.ctxt.ShouldUseTLSGD() {
875875
// Use General Dynamic model for shared libraries
876876
// to support non-glibc dlopen()
877877
return C_TLS_GD

src/cmd/internal/obj/arm64/asm7.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,7 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
21032103
if a.Sym.Type == objabi.STLSBSS {
21042104
// For c-shared/c-archive on standards-compliant systems,
21052105
// use general dynamic model for dlopen compatibility.
2106-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
2106+
if c.ctxt.ShouldUseTLSGD() {
21072107
return C_TLS_GD
21082108
} else {
21092109
return C_TLS_LE

src/cmd/internal/obj/link.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,47 @@ import (
4545
"sync/atomic"
4646
)
4747

48+
// TLSModel represents different Thread Local Storage models
49+
type TLSModel int
50+
51+
const (
52+
TLSModelAuto TLSModel = iota // Automatic selection based on platform and build mode
53+
TLSModelLE // Local Exec - fastest, static executables only
54+
TLSModelIE // Initial Exec - fast, may not work with dlopen on non-glibc
55+
TLSModelGD // General Dynamic - compatible with all dlopen scenarios
56+
)
57+
58+
// ShouldUseTLSGD returns true if General Dynamic TLS model should be used
59+
func (ctxt *Link) ShouldUseTLSGD() bool {
60+
switch ctxt.TLSModel {
61+
case TLSModelGD:
62+
return true
63+
case TLSModelLE, TLSModelIE:
64+
return false
65+
case TLSModelAuto:
66+
// Auto selection logic - matches our current implementation
67+
return ctxt.Flag_shared && (ctxt.Headtype == objabi.Hlinux ||
68+
ctxt.Headtype == objabi.Hfreebsd || ctxt.Headtype == objabi.Hopenbsd)
69+
default:
70+
return false
71+
}
72+
}
73+
74+
// ShouldUseTLSLE returns true if Local Exec TLS model should be used
75+
func (ctxt *Link) ShouldUseTLSLE() bool {
76+
switch ctxt.TLSModel {
77+
case TLSModelLE:
78+
return true
79+
case TLSModelGD, TLSModelIE:
80+
return false
81+
case TLSModelAuto:
82+
// Auto selection: use LE for static executables on supported platforms
83+
return !ctxt.Flag_shared && ctxt.Headtype != objabi.Hwindows && ctxt.Headtype != objabi.Hplan9
84+
default:
85+
return false
86+
}
87+
}
88+
4889
// An Addr is an argument to an instruction.
4990
// The general forms and their encodings are:
5091
//
@@ -1147,6 +1188,7 @@ type Link struct {
11471188
Flag_locationlists bool
11481189
Flag_noRefName bool // do not include referenced symbol names in object file
11491190
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
1191+
TLSModel TLSModel // TLS model selection
11501192
Flag_maymorestack string // If not "", call this function before stack checks
11511193
Bso *bufio.Writer
11521194
Pathname string

src/cmd/internal/obj/loong64/asm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
763763
}
764764
c.instoffset = a.Offset
765765
if a.Sym.Type == objabi.STLSBSS {
766-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
766+
if c.ctxt.ShouldUseTLSGD() {
767767
return C_TLS_GD
768768
} else {
769769
return C_TLS_LE

src/cmd/internal/obj/mips/asm0.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ func (c *ctxt0) aclass(a *obj.Addr) int {
610610
if a.Sym != nil { // use relocation
611611
if a.Sym.Type == objabi.STLSBSS {
612612
// For shared libraries, use general dynamic TLS model
613-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
613+
if c.ctxt.ShouldUseTLSGD() {
614614
return C_TLS_GD
615615
}
616616
return C_TLS

src/cmd/internal/obj/ppc64/asm9.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
910910
} else if a.Sym.Type == objabi.STLSBSS {
911911
// For shared libraries, use general dynamic TLS model
912912
// to support non-glibc dlopen()
913-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
913+
if c.ctxt.ShouldUseTLSGD() {
914914
return C_TLS_GD
915915
}
916916
// Otherwise, use 8 byte local-exec TLS accesses.

src/cmd/internal/obj/riscv/obj.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3904,7 +3904,7 @@ func assemble(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
39043904
break
39053905
}
39063906
if addr.Sym.Type == objabi.STLSBSS {
3907-
if ctxt.Flag_shared && (ctxt.Headtype == objabi.Hlinux || ctxt.Headtype == objabi.Hfreebsd || ctxt.Headtype == objabi.Hopenbsd) {
3907+
if ctxt.ShouldUseTLSGD() {
39083908
rt = objabi.R_RISCV_TLS_GD
39093909
} else {
39103910
rt = objabi.R_RISCV_TLS_LE

src/cmd/internal/obj/s390x/asmz.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ func (c *ctxtz) aclass(a *obj.Addr) int {
582582
}
583583
c.instoffset = a.Offset
584584
if a.Sym.Type == objabi.STLSBSS {
585-
if c.ctxt.Flag_shared && (c.ctxt.Headtype == objabi.Hlinux || c.ctxt.Headtype == objabi.Hfreebsd || c.ctxt.Headtype == objabi.Hopenbsd) {
585+
if c.ctxt.ShouldUseTLSGD() {
586586
return C_TLS_GD // general dynamic model
587587
}
588588
return C_TLS_LE // local exec model

src/cmd/internal/obj/sym.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ func Linknew(arch *LinkArch) *Link {
5757
}
5858

5959
ctxt.Flag_optimize = true
60+
ctxt.TLSModel = TLSModelAuto // Default to automatic TLS model selection
6061
return ctxt
6162
}
6263

0 commit comments

Comments
 (0)