aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/ld/ldmacho.c
diff options
context:
space:
mode:
authorMikkel Krautz <mikkel@krautz.dk>2011-04-07 14:20:42 -0400
committerRuss Cox <rsc@golang.org>2011-04-07 14:20:42 -0400
commit2aceea630f29d3716eea4b8a7d7973f1b3b5e5c8 (patch)
tree5f9b9a6a8be9e5265bc8367cd647ea80a89b59c2 /src/cmd/ld/ldmacho.c
parentcf3323f511e1cf4d07258b54fd982252f0313753 (diff)
downloadgo-2aceea630f29d3716eea4b8a7d7973f1b3b5e5c8.tar.xz
ld: fix Mach-O X86_64_RELOC_SIGNED relocations
Fixes #1658. R=rsc CC=golang-dev https://golang.org/cl/4344066
Diffstat (limited to 'src/cmd/ld/ldmacho.c')
-rw-r--r--src/cmd/ld/ldmacho.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index fbf2f1779b..ad275dca8c 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -422,6 +422,7 @@ void
ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
{
int i, j, is64;
+ uint64 secaddr;
uchar hdr[7*4], *cmdp;
uchar tmp[4];
uchar *dat;
@@ -754,8 +755,29 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
rp->siz = rel->length;
rp->type = 512 + (rel->type<<1) + rel->pcrel;
rp->off = rel->addr;
-
- rp->add = e->e32(s->p+rp->off);
+
+ // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+ if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
+ // Calculate the addend as the offset into the section.
+ //
+ // The rip-relative offset stored in the object file is encoded
+ // as follows:
+ //
+ // movsd 0x00000360(%rip),%xmm0
+ //
+ // To get the absolute address of the value this rip-relative address is pointing
+ // to, we must add the address of the next instruction to it. This is done by
+ // taking the address of the relocation and adding 4 to it (since the rip-relative
+ // offset can at most be 32 bits long). To calculate the offset into the section the
+ // relocation is referencing, we subtract the vaddr of the start of the referenced
+ // section found in the original object file.
+ //
+ // [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+ secaddr = c->seg.sect[rel->symnum-1].addr;
+ rp->add = e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
+ } else
+ rp->add = e->e32(s->p+rp->off);
+
// For i386 Mach-O PC-relative, the addend is written such that
// it *is* the PC being subtracted. Use that to make
// it match our version of PC-relative.