diff options
author | Russ Cox <rsc@golang.org> | 2010-08-04 17:50:22 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2010-08-04 17:50:22 -0700 |
commit | 63be9728040a6d7f525e9107d0615377a36ad009 (patch) | |
tree | 63b8cc4d9f85aca6e1e15b1beeae924a9c7ff68b /src/cmd/6l | |
parent | 6e8d5ba56ecce7a1dc5cec45827398620767c692 (diff) | |
download | go-63be9728040a6d7f525e9107d0615377a36ad009.tar.gz |
amd64: use segment memory for thread-local storage
Returns R14 and R15 to the available register pool.
Plays more nicely with ELF ABI C code.
In particular, our signal handlers will no longer crash
when a signal arrives during execution of a cgo C call.
Fixes issue 720.
R=ken2, r
CC=golang-dev
http://codereview.appspot.com/1847051
Diffstat (limited to 'src/cmd/6l')
-rw-r--r-- | src/cmd/6l/asm.c | 11 | ||||
-rw-r--r-- | src/cmd/6l/l.h | 1 | ||||
-rw-r--r-- | src/cmd/6l/obj.c | 14 | ||||
-rw-r--r-- | src/cmd/6l/pass.c | 24 | ||||
-rw-r--r-- | src/cmd/6l/span.c | 31 |
5 files changed, 74 insertions, 7 deletions
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index b45557ebe..fa419b659 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -821,6 +821,17 @@ asmb(void) ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; phsh(ph, sh); + + /* + * Thread-local storage segment (really just size). + */ + if(tlsoffset != 0) { + ph = newElfPhdr(); + ph->type = PT_TLS; + ph->flags = PF_R; + ph->memsz = -tlsoffset; + ph->align = 8; + } } ph = newElfPhdr(); diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index eb796e203..23ca2232b 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -340,6 +340,7 @@ EXTERN Sym* symlist; EXTERN int32 symsize; EXTERN Prog* textp; EXTERN vlong textsize; +EXTERN int tlsoffset; EXTERN int version; EXTERN Prog zprg; EXTERN int dtype; diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index 724f11296..3b981a612 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -165,6 +165,11 @@ main(int argc, char *argv[]) INITRND = 4096; break; case 6: /* apple MACH */ + /* + * OS X system constant - offset from 0(GS) to our TLS. + * Explained in ../../libcgo/darwin_amd64.c. + */ + tlsoffset = 0x8a0; machoinit(); HEADR = MACHORESERVE; if(INITRND == -1) @@ -176,6 +181,13 @@ main(int argc, char *argv[]) break; case 7: /* elf64 executable */ case 9: /* freebsd */ + /* + * ELF uses TLS offset negative from FS. + * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). + * Also known to ../../pkg/runtime/linux/amd64/sys.s + * and ../../libcgo/linux_amd64.s. + */ + tlsoffset = -16; elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -434,6 +446,8 @@ zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) adrgotype = zsym(pn, f, h); s = a->sym; t = a->type; + if(t == D_INDIR+D_GS) + a->offset += tlsoffset; if(t != D_AUTO && t != D_PARAM) { if(s && adrgotype) s->gotype = adrgotype; diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index 8eced5083..5fedee24a 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -421,6 +421,13 @@ patch(void) s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { + if(HEADTYPE == 7 || HEADTYPE == 9) { + // ELF uses FS instead of GS. + if(p->from.type == D_INDIR+D_GS) + p->from.type = D_INDIR+D_FS; + if(p->to.type == D_INDIR+D_GS) + p->to.type = D_INDIR+D_FS; + } if(p->as == ATEXT) curtext = p; if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { @@ -663,6 +670,15 @@ dostkoff(void) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { + p = appendp(p); // load g into CX + p->as = AMOVQ; + if(HEADTYPE == 7 || HEADTYPE == 9) // ELF uses FS + p->from.type = D_INDIR+D_FS; + else + p->from.type = D_INDIR+D_GS; + p->from.offset = tlsoffset+0; + p->to.type = D_CX; + if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. @@ -672,7 +688,7 @@ dostkoff(void) p = appendp(p); p->as = ACMPQ; - p->from.type = D_INDIR+D_R15; + p->from.type = D_INDIR+D_CX; p->from.offset = 8; p->to.type = D_SP; @@ -694,7 +710,7 @@ dostkoff(void) p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; - p->to.type = D_INDIR+D_R15; + p->to.type = D_INDIR+D_CX; if(q1) { q1->pcond = p; q1 = P; @@ -714,7 +730,7 @@ dostkoff(void) p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; - p->to.type = D_INDIR+D_R15; + p->to.type = D_INDIR+D_CX; } // common @@ -824,7 +840,7 @@ dostkoff(void) // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; - p->from.type = D_INDIR+D_R15; + p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_BX; diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c index 15f931bcb..7e0086e93 100644 --- a/src/cmd/6l/span.c +++ b/src/cmd/6l/span.c @@ -445,6 +445,24 @@ asmlc(void) } int +prefixof(Adr *a) +{ + switch(a->type) { + case D_INDIR+D_CS: + return 0x2e; + case D_INDIR+D_DS: + return 0x3e; + case D_INDIR+D_ES: + return 0x26; + case D_INDIR+D_FS: + return 0x64; + case D_INDIR+D_GS: + return 0x65; + } + return 0; +} + +int oclass(Adr *a) { vlong v; @@ -879,7 +897,7 @@ asmandsz(Adr *a, int r, int rex, int m64) if(t >= D_INDIR) { t -= D_INDIR; rexflag |= (regrex[t] & Rxb) | rex; - if(t == D_NONE) { + if(t == D_NONE || (D_CS <= t && t <= D_GS)) { if(asmode != 64){ *andptr++ = (0 << 6) | (5 << 0) | (r << 3); put4(v); @@ -1173,7 +1191,7 @@ doasm(Prog *p) Prog *q, pp; uchar *t; Movtab *mo; - int z, op, ft, tt, xo, l; + int z, op, ft, tt, xo, l, pre; vlong v; o = opindex[p->as]; @@ -1181,6 +1199,13 @@ doasm(Prog *p) diag("asmins: missing op %P", p); return; } + + pre = prefixof(&p->from); + if(pre) + *andptr++ = pre; + pre = prefixof(&p->to); + if(pre) + *andptr++ = pre; if(p->ft == 0) p->ft = oclass(&p->from); @@ -1748,7 +1773,7 @@ asmins(Prog *p) n = andptr - and; for(np = 0; np < n; np++) { c = and[np]; - if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67) + if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26) break; } memmove(and+np+1, and+np, n-np); |