diff options
Diffstat (limited to 'src/cmd/ld/data.c')
| -rw-r--r-- | src/cmd/ld/data.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index 30e1309d24..e557881e94 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -146,6 +146,7 @@ void relocsym(Sym *s) { Reloc *r; + Sym *rs; Prog p; int32 i, off, siz, fl; vlong o; @@ -176,18 +177,35 @@ relocsym(Sym *s) switch(r->type) { default: o = 0; - if(archreloc(r, s, &o) < 0) + if(isobj || archreloc(r, s, &o) < 0) diag("unknown reloc %d", r->type); break; case D_ADDR: o = symaddr(r->sym) + r->add; + if(isobj && r->sym->type != SCONST) { + if(thechar == '6') + o = 0; + else { + // set up addend for eventual relocation via outer symbol + rs = r->sym; + while(rs->outer != nil) + rs = rs->outer; + o -= symaddr(rs); + } + } break; case D_PCREL: - // r->sym can be null when CALL $(constant) is transformed from absoulte PC to relative PC call. + // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. o = 0; if(r->sym) o += symaddr(r->sym); o += r->add - (s->value + r->off + r->siz); + if(isobj && r->sym->type != SCONST) { + if(thechar == '6') + o = 0; + else + o = r->add - r->siz; + } break; case D_SIZE: o = r->sym->size + r->add; |
