]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/x86, cmd/link/internal/x86: support IE model TLS on linux/386
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Tue, 27 Oct 2015 22:40:22 +0000 (11:40 +1300)
committerMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 18 Nov 2015 01:57:01 +0000 (01:57 +0000)
This includes the first parts of the general approach to PIC: load PC into CX
whenever it is needed. This is going to lead to large binaries and poor
performance but it's a start and easy to get right.

Change-Id: Ic8bf1d0a74284cca0d94a68cf75024e8ab063b4e
Reviewed-on: https://go-review.googlesource.com/16383
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/internal/obj/x86/asm6.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/x86/asm.go
src/cmd/link/internal/x86/obj.go

index 13ab240c6420df44d1b5933c2adfa45431b9113a..416ed71231d4f2197415de2a4ce7d2db33f8b353 100644 (file)
@@ -2018,6 +2018,21 @@ func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
        }
 
        if p.Mode == 32 {
+               if a.Index == REG_TLS && ctxt.Flag_shared != 0 {
+                       // When building for inclusion into a shared library, an instruction of the form
+                       //     MOVL 0(CX)(TLS*1), AX
+                       // becomes
+                       //     mov %gs:(%ecx), %eax
+                       // which assumes that the correct TLS offset has been loaded into %ecx (today
+                       // there is only one TLS variable -- g -- so this is OK). When not building for
+                       // a shared library the instruction it becomes
+                       //     mov 0x0(%ecx), $eax
+                       // and a R_TLS_LE relocation, and so does not require a prefix.
+                       if a.Offset != 0 {
+                               ctxt.Diag("cannot handle non-0 offsets to TLS")
+                       }
+                       return 0x65 // GS
+               }
                return 0
        }
 
@@ -2518,10 +2533,12 @@ func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
                        log.Fatalf("reloc")
                }
 
-               r.Type = obj.R_TLS_LE
-               r.Siz = 4
-               r.Off = -1 // caller must fill in
-               r.Add = a.Offset
+               if ctxt.Flag_shared == 0 {
+                       r.Type = obj.R_TLS_LE
+                       r.Siz = 4
+                       r.Off = -1 // caller must fill in
+                       r.Add = a.Offset
+               }
                return 0
        }
 
@@ -3922,20 +3939,52 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
 
                                                case obj.Hlinux,
                                                        obj.Hnacl:
-                                                       // ELF TLS base is 0(GS).
-                                                       pp.From = p.From
-
-                                                       pp.From.Type = obj.TYPE_MEM
-                                                       pp.From.Reg = REG_GS
-                                                       pp.From.Offset = 0
-                                                       pp.From.Index = REG_NONE
-                                                       pp.From.Scale = 0
-                                                       ctxt.Andptr[0] = 0x65
-                                                       ctxt.Andptr = ctxt.Andptr[1:] // GS
-                                                       ctxt.Andptr[0] = 0x8B
-                                                       ctxt.Andptr = ctxt.Andptr[1:]
-                                                       asmand(ctxt, p, &pp.From, &p.To)
-
+                                                       if ctxt.Flag_shared != 0 {
+                                                               // Note that this is not generating the same insns as the other cases.
+                                                               //     MOV TLS, R_to
+                                                               // becomes
+                                                               //     call __x86.get_pc_thunk.cx
+                                                               //     movl (gotpc + g@gotntpoff)(%ecx),$R_To
+                                                               // which is encoded as
+                                                               //     call __x86.get_pc_thunk.cx
+                                                               //     movq 0(%ecx), R_to
+                                                               // and R_CALL & R_TLS_IE relocs. This all assumes the only tls variable we access
+                                                               // is g, which we can't check here, but will when we assemble the second
+                                                               // instruction.
+                                                               ctxt.Andptr[0] = 0xe8
+                                                               ctxt.Andptr = ctxt.Andptr[1:]
+                                                               r = obj.Addrel(ctxt.Cursym)
+                                                               r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+                                                               r.Type = obj.R_CALL
+                                                               r.Siz = 4
+                                                               r.Sym = obj.Linklookup(ctxt, "__x86.get_pc_thunk.cx", 0)
+                                                               put4(ctxt, 0)
+
+                                                               ctxt.Andptr[0] = 0x8B
+                                                               ctxt.Andptr = ctxt.Andptr[1:]
+                                                               ctxt.Andptr[0] = byte(2<<6 | reg[REG_CX] | (reg[p.To.Reg] << 3))
+                                                               ctxt.Andptr = ctxt.Andptr[1:]
+                                                               r = obj.Addrel(ctxt.Cursym)
+                                                               r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+                                                               r.Type = obj.R_TLS_IE
+                                                               r.Siz = 4
+                                                               r.Add = 2
+                                                               put4(ctxt, 0)
+                                                       } else {
+                                                               // ELF TLS base is 0(GS).
+                                                               pp.From = p.From
+
+                                                               pp.From.Type = obj.TYPE_MEM
+                                                               pp.From.Reg = REG_GS
+                                                               pp.From.Offset = 0
+                                                               pp.From.Index = REG_NONE
+                                                               pp.From.Scale = 0
+                                                               ctxt.Andptr[0] = 0x65
+                                                               ctxt.Andptr = ctxt.Andptr[1:] // GS
+                                                               ctxt.Andptr[0] = 0x8B
+                                                               ctxt.Andptr = ctxt.Andptr[1:]
+                                                               asmand(ctxt, p, &pp.From, &p.To)
+                                                       }
                                                case obj.Hplan9:
                                                        if ctxt.Plan9privates == nil {
                                                                ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
index 9749355ddbe4ad4f1bcadcdafd1c7316e8252525..fc242d8a84033aa566fa1158aee3770e0d0fd3fe 100644 (file)
@@ -1669,7 +1669,7 @@ func stkcheck(up *Chain, depth int) int {
                // should never be called directly.
                // only diagnose the direct caller.
                // TODO(mwhudson): actually think about this.
-               if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() {
+               if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() && Buildmode != BuildmodePIE {
                        Diag("call to external function %s", s.Name)
                }
                return -1
index 7f619b5c3430220e10e5b76993f1671c8eb39156..603aaa4ff1a58bf87e304c710c7c485106479626 100644 (file)
@@ -38,6 +38,30 @@ import (
 )
 
 func gentext() {
+       if !ld.DynlinkingGo() && ld.Buildmode != ld.BuildmodePIE {
+               return
+       }
+
+       thunkfunc := ld.Linklookup(ld.Ctxt, "__x86.get_pc_thunk.cx", 0)
+       thunkfunc.Type = obj.STEXT
+       thunkfunc.Local = true
+       thunkfunc.Reachable = true
+       o := func(op ...uint8) {
+               for _, op1 := range op {
+                       ld.Adduint8(ld.Ctxt, thunkfunc, op1)
+               }
+       }
+       // 8b 0c 24     mov    (%esp),%ecx
+       o(0x8b, 0x0c, 0x24)
+       // c3           ret
+       o(0xc3)
+
+       if ld.Ctxt.Etextp != nil {
+               ld.Ctxt.Etextp.Next = thunkfunc
+       } else {
+               ld.Ctxt.Textp = thunkfunc
+       }
+       ld.Ctxt.Etextp = thunkfunc
 }
 
 func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
@@ -257,6 +281,15 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
                } else {
                        return -1
                }
+
+       case obj.R_TLS_IE:
+               if r.Siz == 4 {
+                       ld.Thearch.Lput(ld.R_386_GOTPC)
+                       ld.Thearch.Lput(uint32(sectoff))
+                       ld.Thearch.Lput(ld.R_386_TLS_GOTIE | uint32(elfsym)<<8)
+               } else {
+                       return -1
+               }
        }
 
        return 0
index ee408f70c648d9ff2b7c06d8b0e91b847281e360..c1535555b3c3ea5919009a7c298dea02c518c173 100644 (file)
@@ -86,6 +86,13 @@ func archinit() {
                ld.Linkmode = ld.LinkInternal
        }
 
+       if ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE || ld.DynlinkingGo() {
+               ld.Linkmode = ld.LinkExternal
+               got := ld.Linklookup(ld.Ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
+               got.Type = obj.SDYNIMPORT
+               got.Reachable = true
+       }
+
        switch ld.HEADTYPE {
        default:
                if ld.Linkmode == ld.LinkAuto {