]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/8l, cmd/internal/ld, cmd/internal/obj/x86: stop incorrectly using the term "inita...
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Thu, 23 Apr 2015 09:53:48 +0000 (21:53 +1200)
committerIan Lance Taylor <iant@golang.org>
Sat, 25 Apr 2015 18:13:15 +0000 (18:13 +0000)
The long comment block in obj6.go:progedit talked about the two code sequences
for accessing g as "local exec" and "initial exec", but really they are both forms
of local exec. This stuff is confusing enough without using the wrong words for
things, so rewrite it to talk about 2-instruction and 1-instruction sequences.
Unfortunately the confusion has made it into code, with the R_TLS_IE relocation
now doing double duty as meaning actual initial exec when externally linking and
boring old local exec when linking internally (half of this is my fault). So this
stops using R_TLS_IE in the local exec case. There is a chance this might break
plan9 or windows, but I don't think so. Next step is working out what the heck is
going on on ARM...

Change-Id: I09da4388210cf49dbc99fd25f5172bbe517cee57
Reviewed-on: https://go-review.googlesource.com/9273
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>

src/cmd/8l/asm.go
src/cmd/internal/ld/data.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go

index 3e8f1afadc13df41a85dfa3b74be0dd2790824c3..e7966f3ac382250c99b055aaf2724f7dce8756c7 100644 (file)
@@ -269,8 +269,7 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
                        return -1
                }
 
-       case obj.R_TLS_LE,
-               obj.R_TLS_IE:
+       case obj.R_TLS_LE:
                if r.Siz == 4 {
                        ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
                } else {
index 5a0ac9e7df31d45a84184d826c1530d6d9030788..07f26200c80e9b0672097e46c4feff5819869a39 100644 (file)
@@ -412,7 +412,13 @@ func relocsym(s *LSym) {
                                break
                        }
 
-                       o = int64(Ctxt.Tlsoffset) + r.Add
+                       if Iself || Ctxt.Headtype == obj.Hplan9 {
+                               o = int64(Ctxt.Tlsoffset) + r.Add
+                       } else if Ctxt.Headtype == obj.Hwindows {
+                               o = r.Add
+                       } else {
+                               log.Fatalf("unexpected R_TLS_LE relocation for %s", Headstr(Ctxt.Headtype))
+                       }
 
                case obj.R_TLS_IE:
                        if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
@@ -426,14 +432,7 @@ func relocsym(s *LSym) {
                                }
                                break
                        }
-
-                       if Iself || Ctxt.Headtype == obj.Hplan9 {
-                               o = int64(Ctxt.Tlsoffset) + r.Add
-                       } else if Ctxt.Headtype == obj.Hwindows {
-                               o = r.Add
-                       } else {
-                               log.Fatalf("unexpected R_TLS_IE relocation for %s", Headstr(Ctxt.Headtype))
-                       }
+                       log.Fatalf("cannot handle R_TLS_IE when linking internally")
 
                case obj.R_ADDR:
                        if Linkmode == LinkExternal && r.Sym.Type != obj.SCONST {
index 39f8941779be49f352b07e6b873c5f684f9a6625..a0add7bf1f62f22b2fce7e44659ce9f66cd3e5bb 100644 (file)
@@ -380,8 +380,23 @@ const (
        R_CALLPOWER
        R_CONST
        R_PCREL
+       // R_TLS (only used on arm currently, and not on android and darwin where tlsg is
+       // a regular variable) resolves to data needed to access the thread-local g. It is
+       // interpreted differently depending on toolchain flags to implement either the
+       // "local exec" or "inital exec" model for tls access.
+       // TODO(mwhudson): change to use R_TLS_LE or R_TLS_IE as appropriate, not having
+       // R_TLS do double duty.
        R_TLS
+       // R_TLS_LE (only used on 386 and amd64 currently) resolves to the offset of the
+       // thread-local g from the thread local base and is used to implement the "local
+       // exec" model for tls access (r.Sym is not set by the compiler for this case but
+       // is set to Tlsg in the linker when externally linking).
        R_TLS_LE
+       // R_TLS_IE (only used on 386 and amd64 currently) resolves to the PC-relative
+       // offset to a GOT slot containing the offset the thread-local g from the thread
+       // local base and is used to implemented the "initial exec" model for tls access
+       // (r.Sym is not set by the compiler for this case but is set to Tlsg in the
+       // linker when externally linking).
        R_TLS_IE
        R_GOTOFF
        R_PLT0
index 480e2ddce62a9c4002a40248b4aa410696652559..0c0cc0454853001f714aff513ac4827ce89d460d 100644 (file)
@@ -2627,7 +2627,7 @@ func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int)
        if REG_AX <= base && base <= REG_R15 {
                if a.Index == REG_TLS && ctxt.Flag_shared == 0 {
                        rel = obj.Reloc{}
-                       rel.Type = obj.R_TLS_IE
+                       rel.Type = obj.R_TLS_LE
                        rel.Siz = 4
                        rel.Sym = nil
                        rel.Add = int64(v)
index e70bdca9df205d87b779e144397f70c4fcf29736..549738bae137801535c62b8f35679fd806b27e65 100644 (file)
@@ -38,7 +38,7 @@ import (
        "math"
 )
 
-func canuselocaltls(ctxt *obj.Link) bool {
+func canuse1insntls(ctxt *obj.Link) bool {
        if ctxt.Arch.Regsize == 4 {
                switch ctxt.Headtype {
                case obj.Hlinux,
@@ -92,29 +92,36 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
        // if the linker needs to adjust the offset, it can. For example:
        //
        //         MOVQ TLS, AX
-       //         MOVQ 8(AX)(TLS*1), CX // load m into CX
+       //         MOVQ 0(AX)(TLS*1), CX // load g into CX
        //
        // On systems that support direct access to the TLS memory, this
        // pair of instructions can be reduced to a direct TLS memory reference:
        //
-       //         MOVQ 8(TLS), CX // load m into CX
+       //         MOVQ 0(TLS), CX // load g into CX
        //
-       // The 2-instruction and 1-instruction forms correspond roughly to
-       // ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
+       // The 2-instruction and 1-instruction forms correspond to the two code
+       // sequences for loading a TLS variable in the local exec model given in "ELF
+       // Handling For Thread-Local Storage".
        //
-       // We applies this rewrite on systems that support the 1-instruction form.
-       // The decision is made using only the operating system (and probably
-       // the -shared flag, eventually), not the link mode. If some link modes
-       // on a particular operating system require the 2-instruction form,
-       // then all builds for that operating system will use the 2-instruction
-       // form, so that the link mode decision can be delayed to link time.
+       // We apply this rewrite on systems that support the 1-instruction form.
+       // The decision is made using only the operating system and the -shared flag,
+       // not the link mode. If some link modes on a particular operating system
+       // require the 2-instruction form, then all builds for that operating system
+       // will use the 2-instruction form, so that the link mode decision can be
+       // delayed to link time.
        //
        // In this way, all supported systems use identical instructions to
        // access TLS, and they are rewritten appropriately first here in
        // liblink and then finally using relocations in the linker.
-
-       if canuselocaltls(ctxt) {
-               // Reduce TLS initial exec model to TLS local exec model.
+       //
+       // When -shared is passed, we leave the code in the 2-instruction form but
+       // assemble (and relocate) them in different ways to generate the initial
+       // exec code sequence. It's a bit of a fluke that this is possible without
+       // rewriting the instructions more comprehensively, and it only does because
+       // we only support a single TLS variable (g).
+
+       if canuse1insntls(ctxt) {
+               // Reduce 2-instruction sequence to 1-instruction sequence.
                // Sequences like
                //      MOVQ TLS, BX
                //      ... off(BX)(TLS*1) ...
@@ -140,13 +147,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
                        p.To.Index = REG_NONE
                }
        } else {
-               // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
-               // The instruction
-               //      MOVQ off(TLS), BX
-               // becomes the sequence
+               // load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
+               // as the 2-instruction sequence if necessary.
+               //      MOVQ 0(TLS), BX
+               // becomes
                //      MOVQ TLS, BX
-               //      MOVQ off(BX)(TLS*1), BX
-               // This allows the C compilers to emit references to m and g using the direct off(TLS) form.
+               //      MOVQ 0(BX)(TLS*1), BX
                if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
                        q := obj.Appendp(ctxt, p)
                        q.As = p.As