mirror of
https://github.com/golang/go
synced 2024-11-19 20:54:39 -07:00
linux/386: use Xen-friendly ELF TLS instruction sequence
Fixes #465. R=iant CC=golang-dev https://golang.org/cl/1665051
This commit is contained in:
parent
bc2ee6b8c6
commit
2d6ae385e1
@ -102,7 +102,7 @@ Dconv(Fmt *fp)
|
|||||||
i = a->type;
|
i = a->type;
|
||||||
if(i >= D_INDIR && i < 2*D_INDIR) {
|
if(i >= D_INDIR && i < 2*D_INDIR) {
|
||||||
if(a->offset)
|
if(a->offset)
|
||||||
sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
|
sprint(str, "%ld(%R)", (long)a->offset, i-D_INDIR);
|
||||||
else
|
else
|
||||||
sprint(str, "(%R)", i-D_INDIR);
|
sprint(str, "(%R)", i-D_INDIR);
|
||||||
goto brk;
|
goto brk;
|
||||||
|
@ -378,7 +378,7 @@ patch(void)
|
|||||||
s = lookup("exit", 0);
|
s = lookup("exit", 0);
|
||||||
vexit = s->value;
|
vexit = s->value;
|
||||||
for(p = firstp; p != P; p = p->link) {
|
for(p = firstp; p != P; p = p->link) {
|
||||||
if(HEADTYPE == 10) {
|
if(HEADTYPE == 10) { // Windows
|
||||||
// Convert
|
// Convert
|
||||||
// op n(GS), reg
|
// op n(GS), reg
|
||||||
// to
|
// to
|
||||||
@ -391,7 +391,7 @@ patch(void)
|
|||||||
&& p->to.type >= D_AX && p->to.type <= D_DI) {
|
&& p->to.type >= D_AX && p->to.type <= D_DI) {
|
||||||
q = appendp(p);
|
q = appendp(p);
|
||||||
q->from = p->from;
|
q->from = p->from;
|
||||||
q->from.type += p->to.type-D_GS;
|
q->from.type = D_INDIR + p->to.type;
|
||||||
q->to = p->to;
|
q->to = p->to;
|
||||||
q->as = p->as;
|
q->as = p->as;
|
||||||
p->as = AMOVL;
|
p->as = AMOVL;
|
||||||
@ -399,6 +399,23 @@ patch(void)
|
|||||||
p->from.offset = 0x2C;
|
p->from.offset = 0x2C;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(HEADTYPE == 7) { // Linux
|
||||||
|
// Running binaries under Xen requires using
|
||||||
|
// MOVL 0(GS), reg
|
||||||
|
// and then off(reg) instead of saying off(GS) directly
|
||||||
|
// when the offset is negative.
|
||||||
|
if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
|
||||||
|
&& p->to.type >= D_AX && p->to.type <= D_DI) {
|
||||||
|
q = appendp(p);
|
||||||
|
q->from = p->from;
|
||||||
|
q->from.type = D_INDIR + p->to.type;
|
||||||
|
q->to = p->to;
|
||||||
|
q->as = p->as;
|
||||||
|
p->as = AMOVL;
|
||||||
|
p->from.type = D_INDIR+D_GS;
|
||||||
|
p->from.offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(p->as == ATEXT)
|
if(p->as == ATEXT)
|
||||||
curtext = p;
|
curtext = p;
|
||||||
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
|
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
|
||||||
@ -616,7 +633,8 @@ dostkoff(void)
|
|||||||
if(pmorestack != P)
|
if(pmorestack != P)
|
||||||
if(!(p->from.scale & NOSPLIT)) {
|
if(!(p->from.scale & NOSPLIT)) {
|
||||||
p = appendp(p); // load g into CX
|
p = appendp(p); // load g into CX
|
||||||
if(HEADTYPE == 10) {
|
switch(HEADTYPE) {
|
||||||
|
case 10: // Windows
|
||||||
p->as = AMOVL;
|
p->as = AMOVL;
|
||||||
p->from.type = D_INDIR+D_FS;
|
p->from.type = D_INDIR+D_FS;
|
||||||
p->from.offset = 0x2c;
|
p->from.offset = 0x2c;
|
||||||
@ -627,7 +645,22 @@ dostkoff(void)
|
|||||||
p->from.type = D_INDIR+D_CX;
|
p->from.type = D_INDIR+D_CX;
|
||||||
p->from.offset = 0;
|
p->from.offset = 0;
|
||||||
p->to.type = D_CX;
|
p->to.type = D_CX;
|
||||||
} else {
|
break;
|
||||||
|
|
||||||
|
case 7: // Linux
|
||||||
|
p->as = AMOVL;
|
||||||
|
p->from.type = D_INDIR+D_GS;
|
||||||
|
p->from.offset = 0;
|
||||||
|
p->to.type = D_CX;
|
||||||
|
|
||||||
|
p = appendp(p);
|
||||||
|
p->as = AMOVL;
|
||||||
|
p->from.type = D_INDIR+D_CX;
|
||||||
|
p->from.offset = tlsoffset + 0;
|
||||||
|
p->to.type = D_CX;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
p->as = AMOVL;
|
p->as = AMOVL;
|
||||||
p->from.type = D_INDIR+D_GS;
|
p->from.type = D_INDIR+D_GS;
|
||||||
p->from.offset = tlsoffset + 0;
|
p->from.offset = tlsoffset + 0;
|
||||||
|
@ -45,11 +45,14 @@ threadentry(void *v)
|
|||||||
* Set specific keys. On Linux/ELF, the thread local storage
|
* Set specific keys. On Linux/ELF, the thread local storage
|
||||||
* is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
|
* is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
|
||||||
* for the two words g and m at %gs:-8 and %gs:-4.
|
* for the two words g and m at %gs:-8 and %gs:-4.
|
||||||
|
* Xen requires us to access those words indirect from %gs:0
|
||||||
|
* which points at itself.
|
||||||
*/
|
*/
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"movl %0, %%gs:-8\n" // MOVL g, -8(GS)
|
"movl %%gs:0, %%eax\n" // MOVL 0(GS), tmp
|
||||||
"movl %1, %%gs:-4\n" // MOVL m, -4(GS)
|
"movl %0, -8(%%eax)\n" // MOVL g, -8(GS)
|
||||||
:: "r"(ts.g), "r"(ts.m)
|
"movl %1, -4(%%eax)\n" // MOVL m, -4(GS)
|
||||||
|
:: "r"(ts.g), "r"(ts.m) : "%eax"
|
||||||
);
|
);
|
||||||
|
|
||||||
crosscall_386(ts.fn);
|
crosscall_386(ts.fn);
|
||||||
|
@ -161,12 +161,12 @@ TEXT clone(SB),7,$0
|
|||||||
// In child on new stack. Reload registers (paranoia).
|
// In child on new stack. Reload registers (paranoia).
|
||||||
MOVL 0(SP), BX // m
|
MOVL 0(SP), BX // m
|
||||||
MOVL 4(SP), DX // g
|
MOVL 4(SP), DX // g
|
||||||
MOVL 8(SP), CX // fn
|
MOVL 8(SP), SI // fn
|
||||||
|
|
||||||
MOVL AX, m_procid(BX) // save tid as m->procid
|
MOVL AX, m_procid(BX) // save tid as m->procid
|
||||||
|
|
||||||
// set up ldt 7+id to point at m->tls.
|
// set up ldt 7+id to point at m->tls.
|
||||||
// m->tls is at m+40. newosproc left the id in tls[0].
|
// newosproc left the id in tls[0].
|
||||||
LEAL m_tls(BX), BP
|
LEAL m_tls(BX), BP
|
||||||
MOVL 0(BP), DI
|
MOVL 0(BP), DI
|
||||||
ADDL $7, DI // m0 is LDT#7. count up.
|
ADDL $7, DI // m0 is LDT#7. count up.
|
||||||
@ -186,7 +186,7 @@ TEXT clone(SB),7,$0
|
|||||||
MOVL DX, g(AX)
|
MOVL DX, g(AX)
|
||||||
MOVL BX, m(AX)
|
MOVL BX, m(AX)
|
||||||
|
|
||||||
CALL stackcheck(SB) // smashes AX
|
CALL stackcheck(SB) // smashes AX, CX
|
||||||
MOVL 0(DX), DX // paranoia; check they are not nil
|
MOVL 0(DX), DX // paranoia; check they are not nil
|
||||||
MOVL 0(BX), BX
|
MOVL 0(BX), BX
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ TEXT clone(SB),7,$0
|
|||||||
CALL emptyfunc(SB)
|
CALL emptyfunc(SB)
|
||||||
POPAL
|
POPAL
|
||||||
|
|
||||||
CALL CX // fn()
|
CALL SI // fn()
|
||||||
CALL exit1(SB)
|
CALL exit1(SB)
|
||||||
MOVL $0x1234, 0x1005
|
MOVL $0x1234, 0x1005
|
||||||
RET
|
RET
|
||||||
@ -247,8 +247,11 @@ TEXT setldt(SB),7,$32
|
|||||||
* To accommodate that rewrite, we translate
|
* To accommodate that rewrite, we translate
|
||||||
* the address here and bump the limit to 0xffffffff (no limit)
|
* the address here and bump the limit to 0xffffffff (no limit)
|
||||||
* so that -8(GS) maps to 0(address).
|
* so that -8(GS) maps to 0(address).
|
||||||
|
* Also, the final 0(GS) (current 8(CX)) has to point
|
||||||
|
* to itself, to mimic ELF.
|
||||||
*/
|
*/
|
||||||
ADDL $0x8, CX // address
|
ADDL $0x8, CX // address
|
||||||
|
MOVL CX, 0(CX)
|
||||||
|
|
||||||
// set up user_desc
|
// set up user_desc
|
||||||
LEAL 16(SP), AX // struct user_desc
|
LEAL 16(SP), AX // struct user_desc
|
||||||
|
@ -24,6 +24,31 @@ case "$GOARCH" in
|
|||||||
echo '#define g(r) 0(r)'
|
echo '#define g(r) 0(r)'
|
||||||
echo '#define m(r) 4(r)'
|
echo '#define m(r) 4(r)'
|
||||||
;;
|
;;
|
||||||
|
linux)
|
||||||
|
# On Linux systems, what we call 0(GS) and 4(GS) for g and m
|
||||||
|
# turn into %gs:-8 and %gs:-4 (using gcc syntax to denote
|
||||||
|
# what the machine sees as opposed to 8l input).
|
||||||
|
# 8l rewrites 0(GS) and 4(GS) into these.
|
||||||
|
#
|
||||||
|
# On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4
|
||||||
|
# directly. Instead, we have to store %gs:0 into a temporary
|
||||||
|
# register and then use -8(%reg) and -4(%reg). This kind
|
||||||
|
# of addressing is correct even when not running Xen.
|
||||||
|
#
|
||||||
|
# 8l can rewrite MOVL 0(GS), CX into the appropriate pair
|
||||||
|
# of mov instructions, using CX as the intermediate register
|
||||||
|
# (safe because CX is about to be written to anyway).
|
||||||
|
# But 8l cannot handle other instructions, like storing into 0(GS),
|
||||||
|
# which is where these macros come into play.
|
||||||
|
# get_tls sets up the temporary and then g and r use it.
|
||||||
|
#
|
||||||
|
# The final wrinkle is that get_tls needs to read from %gs:0,
|
||||||
|
# but in 8l input it's called 8(GS), because 8l is going to
|
||||||
|
# subtract 8 from all the offsets, as described above.
|
||||||
|
echo '#define get_tls(r) MOVL 8(GS), r'
|
||||||
|
echo '#define g(r) -8(r)'
|
||||||
|
echo '#define m(r) -4(r)'
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo '#define get_tls(r)'
|
echo '#define get_tls(r)'
|
||||||
echo '#define g(r) 0(GS)'
|
echo '#define g(r) 0(GS)'
|
||||||
|
Loading…
Reference in New Issue
Block a user