summaryrefslogtreecommitdiff
path: root/src/cmd/6l
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-08-04 17:50:22 -0700
committerRuss Cox <rsc@golang.org>2010-08-04 17:50:22 -0700
commit63be9728040a6d7f525e9107d0615377a36ad009 (patch)
tree63b8cc4d9f85aca6e1e15b1beeae924a9c7ff68b /src/cmd/6l
parent6e8d5ba56ecce7a1dc5cec45827398620767c692 (diff)
downloadgo-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.c11
-rw-r--r--src/cmd/6l/l.h1
-rw-r--r--src/cmd/6l/obj.c14
-rw-r--r--src/cmd/6l/pass.c24
-rw-r--r--src/cmd/6l/span.c31
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);