Commit 6f8b1208 authored by Russ Cox's avatar Russ Cox

cmd/ld: use TLS relocations on ELF systems in external linking mode

Fixes #7719.

LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/87760050
parent 90093f06
...@@ -281,6 +281,13 @@ elfreloc1(Reloc *r, vlong sectoff) ...@@ -281,6 +281,13 @@ elfreloc1(Reloc *r, vlong sectoff)
return -1; return -1;
break; break;
case R_TLS_LE:
if(r->siz == 4)
VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
else
return -1;
break;
case R_PCREL: case R_PCREL:
if(r->siz == 4) { if(r->siz == 4) {
if(r->xsym->type == SDYNIMPORT) if(r->xsym->type == SDYNIMPORT)
......
...@@ -263,7 +263,8 @@ elfreloc1(Reloc *r, vlong sectoff) ...@@ -263,7 +263,8 @@ elfreloc1(Reloc *r, vlong sectoff)
return -1; return -1;
break; break;
case R_TLS: case R_TLS_LE:
case R_TLS_IE:
if(r->siz == 4) if(r->siz == 4)
LPUT(R_386_TLS_LE | elfsym<<8); LPUT(R_386_TLS_LE | elfsym<<8);
else else
......
...@@ -184,9 +184,30 @@ relocsym(LSym *s) ...@@ -184,9 +184,30 @@ relocsym(LSym *s)
o = r->add; o = r->add;
break; break;
case R_TLS_LE: case R_TLS_LE:
if(linkmode == LinkExternal && iself) {
r->done = 0;
r->sym = ctxt->gmsym;
r->xsym = ctxt->gmsym;
r->xadd = r->add;
o = 0;
if(thechar != '6')
o = r->add;
break;
}
o = ctxt->tlsoffset + r->add; o = ctxt->tlsoffset + r->add;
break; break;
case R_TLS_IE: case R_TLS_IE:
if(linkmode == LinkExternal && iself) {
r->done = 0;
r->sym = ctxt->gmsym;
r->xsym = ctxt->gmsym;
r->xadd = r->add;
o = 0;
if(thechar != '6')
o = r->add;
break;
}
if(iself || ctxt->headtype == Hplan9) if(iself || ctxt->headtype == Hplan9)
o = ctxt->tlsoffset + r->add; o = ctxt->tlsoffset + r->add;
else if(ctxt->headtype == Hwindows) else if(ctxt->headtype == Hwindows)
......
...@@ -240,6 +240,7 @@ loadlib(void) ...@@ -240,6 +240,7 @@ loadlib(void)
gmsym->size = 2*PtrSize; gmsym->size = 2*PtrSize;
gmsym->hide = 1; gmsym->hide = 1;
gmsym->reachable = 1; gmsym->reachable = 1;
ctxt->gmsym = gmsym;
// Now that we know the link mode, trim the dynexp list. // Now that we know the link mode, trim the dynexp list.
x = CgoExportDynamic; x = CgoExportDynamic;
......
...@@ -2427,38 +2427,25 @@ asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64) ...@@ -2427,38 +2427,25 @@ asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64)
goto putrelv; goto putrelv;
} }
if(t >= D_AX && t <= D_R15) { if(t >= D_AX && t <= D_R15) {
// TODO: Remove Hwindows condition.
if(v == 0 && t != D_BP && t != D_R13 && (a->index != D_TLS || (ctxt->headtype == Hwindows && a->scale == 2))) {
*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
if(v >= -128 && v < 128 && (a->index != D_TLS || a->scale != 1)) {
ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
if(a->index == D_TLS) { if(a->index == D_TLS) {
Reloc *r;
memset(&rel, 0, sizeof rel); memset(&rel, 0, sizeof rel);
rel.type = R_TLS_IE; rel.type = R_TLS_IE;
rel.siz = 1; rel.siz = 4;
rel.sym = nil; rel.sym = nil;
rel.add = v; rel.add = v;
r = addrel(ctxt->cursym);
*r = rel;
r->off = ctxt->curp->pc + ctxt->andptr + 1 - ctxt->and;
v = 0; v = 0;
} }
if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
if(v >= -128 && v < 128 && rel.siz == 0) {
ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
ctxt->andptr[1] = v; ctxt->andptr[1] = v;
ctxt->andptr += 2; ctxt->andptr += 2;
return; return;
} }
*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
if(a->index == D_TLS) {
memset(&rel, 0, sizeof rel);
rel.type = R_TLS_IE;
rel.siz = 4;
rel.sym = nil;
rel.add = v;
v = 0;
}
goto putrelv; goto putrelv;
} }
goto bad; goto bad;
......
...@@ -1857,43 +1857,25 @@ asmand(Link *ctxt, Addr *a, int r) ...@@ -1857,43 +1857,25 @@ asmand(Link *ctxt, Addr *a, int r)
goto putrelv; goto putrelv;
} }
if(t >= D_AX && t <= D_DI) { if(t >= D_AX && t <= D_DI) {
// TODO(rsc): Remove the Hwindows test.
// As written it produces the same byte-identical output as the code it replaced.
if(v == 0 && rel.siz == 0 && t != D_BP && (a->index != D_TLS || ctxt->headtype == Hwindows)) {
*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
// TODO(rsc): Change a->index tests to check D_TLS.
// Then remove the if statement inside the body.
// As written the code is clearly incorrect for external linking,
// but as written it produces the same byte-identical output as the code it replaced.
if(v >= -128 && v < 128 && rel.siz == 0 && (a->index != D_TLS || ctxt->headtype == Hwindows || a->scale != 1)) {
ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
if(a->index == D_TLS) { if(a->index == D_TLS) {
Reloc *r;
memset(&rel, 0, sizeof rel); memset(&rel, 0, sizeof rel);
rel.type = R_TLS_IE; rel.type = R_TLS_IE;
rel.siz = 1; rel.siz = 4;
rel.sym = nil; rel.sym = nil;
rel.add = v; rel.add = v;
r = addrel(ctxt->cursym);
*r = rel;
r->off = ctxt->curp->pc + ctxt->andptr + 1 - ctxt->and;
v = 0; v = 0;
} }
if(v == 0 && rel.siz == 0 && t != D_BP) {
*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
if(v >= -128 && v < 128 && rel.siz == 0) {
ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
ctxt->andptr[1] = v; ctxt->andptr[1] = v;
ctxt->andptr += 2; ctxt->andptr += 2;
return; return;
} }
*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3); *ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
if(a->index == D_TLS) {
memset(&rel, 0, sizeof rel);
rel.type = R_TLS_IE;
rel.siz = 4;
rel.sym = nil;
rel.add = v;
v = 0;
}
goto putrelv; goto putrelv;
} }
goto bad; goto bad;
......
...@@ -131,6 +131,7 @@ dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | linux-386 | linu ...@@ -131,6 +131,7 @@ dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | linux-386 | linu
go test -ldflags '-linkmode=external' || exit 1 go test -ldflags '-linkmode=external' || exit 1
go test -ldflags '-linkmode=auto' ../testtls || exit 1 go test -ldflags '-linkmode=auto' ../testtls || exit 1
go test -ldflags '-linkmode=external' ../testtls || exit 1 go test -ldflags '-linkmode=external' ../testtls || exit 1
go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1
esac esac
) || exit $? ) || exit $?
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment