}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- USED(add); // written to obj file by ../ld/data.c's reloc
-
- LPUT(off);
+ int32 elfsym;
+
+ LPUT(sectoff);
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
{
int32 off;
uchar siz;
+ uchar done;
int16 type;
int32 add;
+ int32 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- VPUT(off);
+ int32 elfsym;
+ VPUT(sectoff);
+
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
else
return -1;
- add -= r->siz;
break;
}
- VPUT(add);
+ VPUT(r->xadd);
return 0;
}
{
int32 off;
uchar siz;
+ uchar done;
int32 type;
int64 add;
+ int64 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
}
int
-elfreloc1(Reloc *r, vlong off, int32 elfsym, vlong add)
+elfreloc1(Reloc *r, vlong sectoff)
{
- USED(add); // written to obj file by ../ld/data.c's reloc
+ int32 elfsym;
- LPUT(off);
+ LPUT(sectoff);
+ elfsym = r->xsym->elfsym;
switch(r->type) {
default:
return -1;
{
int32 off;
uchar siz;
+ uchar done;
int32 type;
int32 add;
+ int32 xadd;
Sym* sym;
+ Sym* xsym;
};
struct Prog
cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; r<s->r+s->nr; r++) {
+ r->done = 1;
off = r->off;
siz = r->siz;
if(off < 0 || off+siz > s->np) {
diag("unknown reloc %d", r->type);
break;
case D_ADDR:
- o = symaddr(r->sym) + r->add;
if(isobj && r->sym->type != SCONST) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
+ }
+ r->xsym = rs;
+
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);
- }
+ else
+ o = r->xadd;
+ break;
}
+ o = symaddr(r->sym) + r->add;
break;
case D_PCREL:
// 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 && r->sym->sect != cursym->sect) {
+ if(isobj && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
+ r->done = 0;
+
+ // set up addend for eventual relocation via outer symbol.
+ rs = r->sym;
+ r->xadd = r->add;
+ while(rs->outer != nil) {
+ r->xadd += symaddr(rs) - symaddr(rs->outer);
+ rs = rs->outer;
+ }
+ r->xsym = rs;
+ r->xadd -= r->siz;
+
if(thechar == '6')
o = 0;
else
- o = r->add - r->siz;
+ o = r->xadd;
+ break;
}
+ o = 0;
+ if(r->sym)
+ o += symaddr(r->sym);
+ o += r->add - (s->value + r->off + r->siz);
break;
case D_SIZE:
o = r->sym->size + r->add;
void
elfrelocsect(Section *sect, Sym *first)
{
- Sym *sym, *rs;
+ Sym *sym;
int32 eaddr;
Reloc *r;
- int64 add;
// If main section is SHT_NOBITS, nothing to relocate.
// Also nothing to relocate in .shstrtab.
cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
- // Ignore relocations handled by reloc already.
- switch(r->type) {
- case D_SIZE:
+ if(r->done)
+ continue;
+ if(r->xsym == nil) {
+ diag("missing xsym in relocation");
continue;
- case D_ADDR:
- case D_PCREL:
- if(r->sym->type == SCONST)
- continue; // handled in data.c:/^relocsym
- if(r->type == D_PCREL && r->sym->sect == sym->sect)
- continue; // handled in data.c:/^relocsym
- break;
- }
-
- add = r->add;
- rs = r->sym;
- while(rs->outer != nil) {
- add += rs->value - rs->outer->value;
- rs = rs->outer;
}
-
- if(rs->elfsym == 0)
- diag("reloc %d to non-elf symbol %s (rs=%s) %d", r->type, r->sym->name, rs->name, rs->type);
-
- if(elfreloc1(r, sym->value - sect->vaddr + r->off, rs->elfsym, add) < 0)
+ if(r->xsym->elfsym == 0)
+ diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
+ if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
extern char freebsddynld[];
extern char netbsddynld[];
extern char openbsddynld[];
-int elfreloc1(Reloc*, vlong off, int32 elfsym, vlong add);
+int elfreloc1(Reloc*, vlong sectoff);
EXTERN int elfstrsize;
EXTERN char* elfstrdat;