]> Cypherpunks repositories - gostls13.git/commitdiff
liblink: introduce way to avoid pc-relative addressing
authorRuss Cox <rsc@golang.org>
Mon, 25 Aug 2014 22:45:29 +0000 (18:45 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 25 Aug 2014 22:45:29 +0000 (18:45 -0400)
For Solaris. Sigh.

LGTM=dave
R=aram, iant, dave
CC=golang-codereviews
https://golang.org/cl/129540043

src/liblink/asm6.c

index 576f3497501a659f3edb38eb319afde5c613e47b..999507650dcd1e30ac461a00b9ca036b30c244f7 100644 (file)
@@ -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;
                }