diff options
Diffstat (limited to 'src/cmd/8l/span.c')
-rw-r--r-- | src/cmd/8l/span.c | 54 |
1 files changed, 52 insertions, 2 deletions
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index b828d8645..980186b16 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -32,6 +32,7 @@ #include "l.h" #include "../ld/lib.h" +#include "../ld/elf.h" static int32 vaddr(Adr*, Reloc*); @@ -559,6 +560,14 @@ vaddr(Adr *a, Reloc *r) return v; } +static int +istls(Adr *a) +{ + if(HEADTYPE == Hlinux) + return a->index == D_GS; + return a->type == D_INDIR+D_GS; +} + void asmand(Adr *a, int r) { @@ -569,7 +578,7 @@ asmand(Adr *a, int r) v = a->offset; t = a->type; rel.siz = 0; - if(a->index != D_NONE) { + if(a->index != D_NONE && a->index != D_FS && a->index != D_GS) { if(t < D_INDIR || t >= 2*D_INDIR) { switch(t) { default: @@ -658,7 +667,7 @@ asmand(Adr *a, int r) *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3); return; } - if(v >= -128 && v < 128 && rel.siz == 0) { + if(v >= -128 && v < 128 && rel.siz == 0 && a->index != D_FS && a->index != D_GS) { andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3); andptr[1] = v; andptr += 2; @@ -680,7 +689,29 @@ putrelv: r = addrel(cursym); *r = rel; r->off = curp->pc + andptr - and; + } else if(iself && linkmode == LinkExternal && istls(a) && HEADTYPE != Hopenbsd) { + Reloc *r; + Sym *s; + + r = addrel(cursym); + r->off = curp->pc + andptr - and; + r->add = 0; + r->xadd = 0; + r->siz = 4; + r->type = D_TLS; + if(a->offset == tlsoffset+0) + s = lookup("runtime.g", 0); + else + s = lookup("runtime.m", 0); + s->type = STLSBSS; + s->reachable = 1; + s->hide = 1; + s->size = PtrSize; + r->sym = s; + r->xsym = s; + v = 0; } + put4(v); return; @@ -1003,11 +1034,23 @@ found: *andptr++ = op; break; + case Zlitm_r: + for(; op = o->op[z]; z++) + *andptr++ = op; + asmand(&p->from, reg[p->to.type]); + break; + case Zm_r: *andptr++ = op; asmand(&p->from, reg[p->to.type]); break; + case Zm2_r: + *andptr++ = op; + *andptr++ = o->op[z+1]; + asmand(&p->from, reg[p->to.type]); + break; + case Zm_r_xm: mediaop(o, op, t[3], z); asmand(&p->from, reg[p->to.type]); @@ -1019,6 +1062,13 @@ found: *andptr++ = p->to.offset; break; + case Zibm_r: + while ((op = o->op[z++]) != 0) + *andptr++ = op; + asmand(&p->from, reg[p->to.type]); + *andptr++ = p->to.offset; + break; + case Zaut_r: *andptr++ = 0x8d; /* leal */ if(p->from.type != D_ADDR) |