aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ld/data.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/data.c')
-rw-r--r--src/cmd/ld/data.c22
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;