summaryrefslogtreecommitdiff
path: root/src/liblink
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-08-25 18:45:29 -0400
committerRuss Cox <rsc@golang.org>2014-08-25 18:45:29 -0400
commit439c80a2788dbd86dbf335776a03d6077fcb866d (patch)
tree7a503df42a21c6134289a7c4de3b3253a6157946 /src/liblink
parent6b31ff107290ad829676037dd1d9bdf5fd846346 (diff)
downloadgo-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.c35
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;
}