mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/internal/obj/x86, cmd/link/internal/x86: support IE model TLS on linux/386
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>
This commit is contained in:
parent
61da0e92d0
commit
3bf61fb2e5
4 changed files with 106 additions and 17 deletions
|
|
@ -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")
|
||||
}
|
||||
|
||||
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,6 +3939,38 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
|
|||
|
||||
case obj.Hlinux,
|
||||
obj.Hnacl:
|
||||
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
|
||||
|
||||
|
|
@ -3935,7 +3984,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) {
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue