diff options
author | Russ Cox <rsc@golang.org> | 2014-08-25 18:45:29 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-08-25 18:45:29 -0400 |
commit | 439c80a2788dbd86dbf335776a03d6077fcb866d (patch) | |
tree | 7a503df42a21c6134289a7c4de3b3253a6157946 /src/liblink | |
parent | 6b31ff107290ad829676037dd1d9bdf5fd846346 (diff) | |
download | go-439c80a2788dbd86dbf335776a03d6077fcb866d.tar.gz |
liblink: introduce way to avoid pc-relative addressing
For Solaris. Sigh.
LGTM=dave
R=aram, iant, dave
CC=golang-codereviews
https://codereview.appspot.com/129540043
Diffstat (limited to 'src/liblink')
-rw-r--r-- | src/liblink/asm6.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c index 576f34975..999507650 100644 --- a/src/liblink/asm6.c +++ b/src/liblink/asm6.c @@ -1535,6 +1535,19 @@ static Optab optab[] = static Optab* opindex[ALAST+1]; static vlong vaddr(Link*, Addr*, Reloc*); +// isextern reports whether s describes an external symbol that must avoid pc-relative addressing. +// This happens on systems like Solaris that call .so functions instead of system calls. +// It does not seem to be necessary for any other systems. This is probably working +// around a Solaris-specific bug that should be fixed differently, but we don't know +// what that bug is. And this does fix it. +static int +isextern(LSym *s) +{ + // All the Solaris dynamic imports from libc.so begin with "libc·", which + // the compiler rewrites to "libc." by the time liblink gets it. + return strncmp(s->name, "libc.", 5) == 0; +} + // single-instruction no-ops of various lengths. // constructed by hand and disassembled with gdb to verify. // see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion. @@ -1932,6 +1945,8 @@ oclass(Link *ctxt, Addr *a) switch(a->index) { case D_EXTERN: case D_STATIC: + if(a->sym != nil && isextern(a->sym)) + return Yi32; return Yiauto; // use pc-relative addressing case D_AUTO: case D_PARAM: @@ -2109,7 +2124,7 @@ oclass(Link *ctxt, Addr *a) return Yi32; /* unsigned */ return Yi64; } - return Yi32; /* TO DO: D_ADDR as Yi64 */ + return Yi32; case D_BRANCH: return Ybr; @@ -2282,12 +2297,17 @@ vaddr(Link *ctxt, Addr *a, Reloc *r) ctxt->diag("need reloc for %D", a); sysfatal("reloc"); } - r->siz = 4; // TODO: 8 for external symbols + if(isextern(s)) { + r->siz = 4; + r->type = R_ADDR; + } else { + r->siz = 4; + r->type = R_PCREL; + } r->off = -1; // caller must fill in r->sym = s; r->add = v; v = 0; - r->type = R_PCREL; if(s->type == STLSBSS) { r->xadd = r->add - r->siz; r->type = R_TLS; @@ -2327,6 +2347,13 @@ asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64) switch(t) { default: goto bad; + case D_EXTERN: + case D_STATIC: + if(!isextern(a->sym)) + goto bad; + t = D_NONE; + v = vaddr(ctxt, a, &rel); + break; case D_AUTO: case D_PARAM: t = D_SP; @@ -2386,7 +2413,7 @@ asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64) ctxt->rexflag |= (regrex[t] & Rxb) | rex; if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) { - if(t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) { + if((a->sym == nil || !isextern(a->sym)) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) { *ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3); goto putrelv; } |