summaryrefslogtreecommitdiff
path: root/src/cmd/ld/ldmacho.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/ld/ldmacho.c')
-rw-r--r--src/cmd/ld/ldmacho.c821
1 files changed, 0 insertions, 821 deletions
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
deleted file mode 100644
index abbc3b3cd..000000000
--- a/src/cmd/ld/ldmacho.c
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
- Copyright © 2004 Russ Cox.
- Portions Copyright © 2008-2010 Google Inc.
- Portions Copyright © 2010 The Go Authors.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-*/
-
-#include "l.h"
-#include "lib.h"
-
-enum {
- MACHO_FAKE_GOTPCREL = 100, // from macho.h
-
- N_EXT = 0x01,
- N_TYPE = 0x1e,
- N_STAB = 0xe0,
-};
-
-typedef struct MachoObj MachoObj;
-typedef struct MachoCmd MachoCmd;
-typedef struct MachoSeg MachoSeg;
-typedef struct MachoSect MachoSect;
-typedef struct MachoRel MachoRel;
-typedef struct MachoSymtab MachoSymtab;
-typedef struct MachoSym MachoSym;
-typedef struct MachoDysymtab MachoDysymtab;
-
-enum
-{
- MachoCpuVax = 1,
- MachoCpu68000 = 6,
- MachoCpu386 = 7,
- MachoCpuAmd64 = 0x1000007,
- MachoCpuMips = 8,
- MachoCpu98000 = 10,
- MachoCpuHppa = 11,
- MachoCpuArm = 12,
- MachoCpu88000 = 13,
- MachoCpuSparc = 14,
- MachoCpu860 = 15,
- MachoCpuAlpha = 16,
- MachoCpuPower = 18,
-
- MachoCmdSegment = 1,
- MachoCmdSymtab = 2,
- MachoCmdSymseg = 3,
- MachoCmdThread = 4,
- MachoCmdDysymtab = 11,
- MachoCmdSegment64 = 25,
-
- MachoFileObject = 1,
- MachoFileExecutable = 2,
- MachoFileFvmlib = 3,
- MachoFileCore = 4,
- MachoFilePreload = 5,
-};
-
-struct MachoSeg
-{
- char name[16+1];
- uint64 vmaddr;
- uint64 vmsize;
- uint32 fileoff;
- uint32 filesz;
- uint32 maxprot;
- uint32 initprot;
- uint32 nsect;
- uint32 flags;
- MachoSect *sect;
-};
-
-struct MachoSect
-{
- char name[16+1];
- char segname[16+1];
- uint64 addr;
- uint64 size;
- uint32 off;
- uint32 align;
- uint32 reloff;
- uint32 nreloc;
- uint32 flags;
- uint32 res1;
- uint32 res2;
- Sym *sym;
-
- MachoRel *rel;
-};
-
-struct MachoRel
-{
- uint32 addr;
- uint32 symnum;
- uint8 pcrel;
- uint8 length;
- uint8 extrn;
- uint8 type;
- uint8 scattered;
- uint32 value;
-};
-
-struct MachoSymtab
-{
- uint32 symoff;
- uint32 nsym;
- uint32 stroff;
- uint32 strsize;
-
- char *str;
- MachoSym *sym;
-};
-
-struct MachoSym
-{
- char *name;
- uint8 type;
- uint8 sectnum;
- uint16 desc;
- char kind;
- uint64 value;
- Sym *sym;
-};
-
-struct MachoDysymtab
-{
- uint32 ilocalsym;
- uint32 nlocalsym;
- uint32 iextdefsym;
- uint32 nextdefsym;
- uint32 iundefsym;
- uint32 nundefsym;
- uint32 tocoff;
- uint32 ntoc;
- uint32 modtaboff;
- uint32 nmodtab;
- uint32 extrefsymoff;
- uint32 nextrefsyms;
- uint32 indirectsymoff;
- uint32 nindirectsyms;
- uint32 extreloff;
- uint32 nextrel;
- uint32 locreloff;
- uint32 nlocrel;
- uint32 *indir;
-};
-
-struct MachoCmd
-{
- int type;
- uint32 off;
- uint32 size;
- MachoSeg seg;
- MachoSymtab sym;
- MachoDysymtab dsym;
-};
-
-struct MachoObj
-{
- Biobuf *f;
- int64 base; // off in f where Mach-O begins
- int64 len; // length of Mach-O
- int is64;
- char *name;
-
- Endian *e;
- uint cputype;
- uint subcputype;
- uint32 filetype;
- uint32 flags;
- MachoCmd *cmd;
- uint ncmd;
-};
-
-static int
-unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
-{
- uint32 (*e4)(uchar*);
- uint64 (*e8)(uchar*);
- MachoSect *s;
- int i;
-
- e4 = m->e->e32;
- e8 = m->e->e64;
-
- c->type = type;
- c->size = sz;
- switch(type){
- default:
- return -1;
- case MachoCmdSegment:
- if(sz < 56)
- return -1;
- strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
- c->seg.vmaddr = e4(p+24);
- c->seg.vmsize = e4(p+28);
- c->seg.fileoff = e4(p+32);
- c->seg.filesz = e4(p+36);
- c->seg.maxprot = e4(p+40);
- c->seg.initprot = e4(p+44);
- c->seg.nsect = e4(p+48);
- c->seg.flags = e4(p+52);
- c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
- if(sz < 56+c->seg.nsect*68)
- return -1;
- p += 56;
- for(i=0; i<c->seg.nsect; i++) {
- s = &c->seg.sect[i];
- strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
- strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
- s->addr = e4(p+32);
- s->size = e4(p+36);
- s->off = e4(p+40);
- s->align = e4(p+44);
- s->reloff = e4(p+48);
- s->nreloc = e4(p+52);
- s->flags = e4(p+56);
- s->res1 = e4(p+60);
- s->res2 = e4(p+64);
- p += 68;
- }
- break;
- case MachoCmdSegment64:
- if(sz < 72)
- return -1;
- strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
- c->seg.vmaddr = e8(p+24);
- c->seg.vmsize = e8(p+32);
- c->seg.fileoff = e8(p+40);
- c->seg.filesz = e8(p+48);
- c->seg.maxprot = e4(p+56);
- c->seg.initprot = e4(p+60);
- c->seg.nsect = e4(p+64);
- c->seg.flags = e4(p+68);
- c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
- if(sz < 72+c->seg.nsect*80)
- return -1;
- p += 72;
- for(i=0; i<c->seg.nsect; i++) {
- s = &c->seg.sect[i];
- strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
- strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
- s->addr = e8(p+32);
- s->size = e8(p+40);
- s->off = e4(p+48);
- s->align = e4(p+52);
- s->reloff = e4(p+56);
- s->nreloc = e4(p+60);
- s->flags = e4(p+64);
- s->res1 = e4(p+68);
- s->res2 = e4(p+72);
- // p+76 is reserved
- p += 80;
- }
- break;
- case MachoCmdSymtab:
- if(sz < 24)
- return -1;
- c->sym.symoff = e4(p+8);
- c->sym.nsym = e4(p+12);
- c->sym.stroff = e4(p+16);
- c->sym.strsize = e4(p+20);
- break;
- case MachoCmdDysymtab:
- if(sz < 80)
- return -1;
- c->dsym.ilocalsym = e4(p+8);
- c->dsym.nlocalsym = e4(p+12);
- c->dsym.iextdefsym = e4(p+16);
- c->dsym.nextdefsym = e4(p+20);
- c->dsym.iundefsym = e4(p+24);
- c->dsym.nundefsym = e4(p+28);
- c->dsym.tocoff = e4(p+32);
- c->dsym.ntoc = e4(p+36);
- c->dsym.modtaboff = e4(p+40);
- c->dsym.nmodtab = e4(p+44);
- c->dsym.extrefsymoff = e4(p+48);
- c->dsym.nextrefsyms = e4(p+52);
- c->dsym.indirectsymoff = e4(p+56);
- c->dsym.nindirectsyms = e4(p+60);
- c->dsym.extreloff = e4(p+64);
- c->dsym.nextrel = e4(p+68);
- c->dsym.locreloff = e4(p+72);
- c->dsym.nlocrel = e4(p+76);
- break;
- }
- return 0;
-}
-
-static int
-macholoadrel(MachoObj *m, MachoSect *sect)
-{
- MachoRel *rel, *r;
- uchar *buf, *p;
- int i, n;
- uint32 v;
-
- if(sect->rel != nil || sect->nreloc == 0)
- return 0;
- rel = mal(sect->nreloc * sizeof r[0]);
- n = sect->nreloc * 8;
- buf = mal(n);
- if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
- return -1;
- for(i=0; i<sect->nreloc; i++) {
- r = &rel[i];
- p = buf+i*8;
- r->addr = m->e->e32(p);
-
- // TODO(rsc): Wrong interpretation for big-endian bitfields?
- if(r->addr & 0x80000000) {
- // scatterbrained relocation
- r->scattered = 1;
- v = r->addr >> 24;
- r->addr &= 0xFFFFFF;
- r->type = v & 0xF;
- v >>= 4;
- r->length = 1<<(v&3);
- v >>= 2;
- r->pcrel = v & 1;
- r->value = m->e->e32(p+4);
- } else {
- v = m->e->e32(p+4);
- r->symnum = v & 0xFFFFFF;
- v >>= 24;
- r->pcrel = v&1;
- v >>= 1;
- r->length = 1<<(v&3);
- v >>= 2;
- r->extrn = v&1;
- v >>= 1;
- r->type = v;
- }
- }
- sect->rel = rel;
- return 0;
-}
-
-static int
-macholoaddsym(MachoObj *m, MachoDysymtab *d)
-{
- uchar *p;
- int i, n;
-
- n = d->nindirectsyms;
-
- p = mal(n*4);
- if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
- return -1;
-
- d->indir = (uint32*)p;
- for(i=0; i<n; i++)
- d->indir[i] = m->e->e32(p+4*i);
- return 0;
-}
-
-static int
-macholoadsym(MachoObj *m, MachoSymtab *symtab)
-{
- char *strbuf;
- uchar *symbuf, *p;
- int i, n, symsize;
- MachoSym *sym, *s;
- uint32 v;
-
- if(symtab->sym != nil)
- return 0;
-
- strbuf = mal(symtab->strsize);
- if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
- return -1;
-
- symsize = 12;
- if(m->is64)
- symsize = 16;
- n = symtab->nsym * symsize;
- symbuf = mal(n);
- if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
- return -1;
- sym = mal(symtab->nsym * sizeof sym[0]);
- p = symbuf;
- for(i=0; i<symtab->nsym; i++) {
- s = &sym[i];
- v = m->e->e32(p);
- if(v >= symtab->strsize)
- return -1;
- s->name = strbuf + v;
- s->type = p[4];
- s->sectnum = p[5];
- s->desc = m->e->e16(p+6);
- if(m->is64)
- s->value = m->e->e64(p+8);
- else
- s->value = m->e->e32(p+8);
- p += symsize;
- }
- symtab->str = strbuf;
- symtab->sym = sym;
- return 0;
-}
-
-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;
- ulong ncmd, cmdsz, ty, sz, off;
- MachoObj *m;
- Endian *e;
- int64 base;
- MachoSect *sect;
- MachoRel *rel;
- Sym *s, *outer;
- MachoCmd *c;
- MachoSymtab *symtab;
- MachoDysymtab *dsymtab;
- MachoSym *sym;
- Reloc *r, *rp;
- char *name;
-
- USED(pkg);
- version++;
- base = Boffset(f);
- if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
- goto bad;
-
- if((be.e32(hdr)&~1) == 0xFEEDFACE){
- e = &be;
- }else if((le.e32(hdr)&~1) == 0xFEEDFACE){
- e = &le;
- }else{
- werrstr("bad magic - not mach-o file");
- goto bad;
- }
-
- is64 = e->e32(hdr) == 0xFEEDFACF;
- ncmd = e->e32(hdr+4*4);
- cmdsz = e->e32(hdr+5*4);
- if(ncmd > 0x10000 || cmdsz >= 0x01000000){
- werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
- goto bad;
- }
- if(is64)
- Bread(f, tmp, 4); // skip reserved word in header
-
- m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
- m->f = f;
- m->e = e;
- m->cputype = e->e32(hdr+1*4);
- m->subcputype = e->e32(hdr+2*4);
- m->filetype = e->e32(hdr+3*4);
- m->ncmd = ncmd;
- m->flags = e->e32(hdr+6*4);
- m->is64 = is64;
- m->base = base;
- m->len = len;
- m->name = pn;
-
- switch(thechar) {
- default:
- diag("%s: mach-o %s unimplemented", thestring);
- return;
- case '6':
- if(e != &le || m->cputype != MachoCpuAmd64) {
- diag("%s: mach-o object but not amd64", pn);
- return;
- }
- break;
- case '8':
- if(e != &le || m->cputype != MachoCpu386) {
- diag("%s: mach-o object but not 386", pn);
- return;
- }
- break;
- }
-
- m->cmd = (MachoCmd*)(m+1);
- off = sizeof hdr;
- cmdp = (uchar*)(m->cmd+ncmd);
- if(Bread(f, cmdp, cmdsz) != cmdsz){
- werrstr("reading cmds: %r");
- goto bad;
- }
-
- // read and parse load commands
- c = nil;
- symtab = nil;
- dsymtab = nil;
- for(i=0; i<ncmd; i++){
- ty = e->e32(cmdp);
- sz = e->e32(cmdp+4);
- m->cmd[i].off = off;
- unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
- cmdp += sz;
- off += sz;
- if(ty == MachoCmdSymtab) {
- if(symtab != nil) {
- werrstr("multiple symbol tables");
- goto bad;
- }
- symtab = &m->cmd[i].sym;
- macholoadsym(m, symtab);
- }
- if(ty == MachoCmdDysymtab) {
- dsymtab = &m->cmd[i].dsym;
- macholoaddsym(m, dsymtab);
- }
- if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
- if(c != nil) {
- werrstr("multiple load commands");
- goto bad;
- }
- c = &m->cmd[i];
- }
- }
-
- // load text and data segments into memory.
- // they are not as small as the load commands, but we'll need
- // the memory anyway for the symbol images, so we might
- // as well use one large chunk.
- if(c == nil) {
- werrstr("no load command");
- goto bad;
- }
- if(symtab == nil) {
- // our work is done here - no symbols means nothing can refer to this file
- return;
- }
-
- if(c->seg.fileoff+c->seg.filesz >= len) {
- werrstr("load segment out of range");
- goto bad;
- }
-
- dat = mal(c->seg.filesz);
- if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
- werrstr("cannot load object data: %r");
- goto bad;
- }
-
- for(i=0; i<c->seg.nsect; i++) {
- sect = &c->seg.sect[i];
- if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
- continue;
- if(strcmp(sect->name, "__eh_frame") == 0)
- continue;
- name = smprint("%s(%s/%s)", pn, sect->segname, sect->name);
- s = lookup(name, version);
- if(s->type != 0) {
- werrstr("duplicate %s/%s", sect->segname, sect->name);
- goto bad;
- }
- free(name);
- s->p = dat + sect->addr - c->seg.vmaddr;
- s->np = sect->size;
- s->size = s->np;
-
- if(strcmp(sect->segname, "__TEXT") == 0) {
- if(strcmp(sect->name, "__text") == 0)
- s->type = STEXT;
- else
- s->type = SRODATA;
- } else {
- if (strcmp(sect->name, "__bss") == 0) {
- s->type = SBSS;
- s->np = 0;
- } else
- s->type = SDATA;
- }
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
- sect->sym = s;
- }
-
- // enter sub-symbols into symbol table.
- // have to guess sizes from next symbol.
- for(i=0; i<symtab->nsym; i++) {
- int v;
- sym = &symtab->sym[i];
- if(sym->type&N_STAB)
- continue;
- // TODO: check sym->type against outer->type.
- name = sym->name;
- if(name[0] == '_' && name[1] != '\0')
- name++;
- v = 0;
- if(!(sym->type&N_EXT))
- v = version;
- s = lookup(name, v);
- sym->sym = s;
- if(sym->sectnum == 0) // undefined
- continue;
- if(sym->sectnum > c->seg.nsect) {
- werrstr("reference to invalid section %d", sym->sectnum);
- goto bad;
- }
- sect = &c->seg.sect[sym->sectnum-1];
- outer = sect->sym;
- if(outer == nil) {
- werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
- continue;
- }
- s->type = outer->type | SSUB;
- s->sub = outer->sub;
- outer->sub = s;
- s->outer = outer;
- s->value = sym->value - sect->addr;
- if(i+1 < symtab->nsym)
- s->size = (sym+1)->value - sym->value;
- else
- s->size = sect->addr + sect->size - sym->value;
- if(!s->dynexport) {
- s->dynimplib = nil; // satisfy dynimport
- s->dynimpname = nil; // satisfy dynimport
- }
- if(outer->type == STEXT) {
- Prog *p;
-
- if(s->text != P)
- diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
- // build a TEXT instruction with a unique pc
- // just to make the rest of the linker happy.
- // TODO: this is too 6l-specific ?
- p = prg();
- p->as = ATEXT;
- p->from.type = D_EXTERN;
- p->from.sym = s;
- p->textflag = 7;
- p->to.type = D_CONST;
- p->link = nil;
- p->pc = pc++;
- s->text = p;
-
- etextp->next = s;
- etextp = s;
- }
- sym->sym = s;
- }
-
- // load relocations
- for(i=0; i<c->seg.nsect; i++) {
- sect = &c->seg.sect[i];
- if((s = sect->sym) == S)
- continue;
- macholoadrel(m, sect);
- if(sect->rel == nil)
- continue;
- r = mal(sect->nreloc*sizeof r[0]);
- rp = r;
- rel = sect->rel;
- for(j=0; j<sect->nreloc; j++, rel++) {
- if(rel->scattered) {
- int k;
- MachoSect *ks;
-
- if(thechar != '8')
- diag("unexpected scattered relocation");
-
- // on 386, rewrite scattered 4/1 relocation into
- // the pseudo-pc-relative reference that it is.
- // assume that the second in the pair is in this section
- // and use that as the pc-relative base.
- if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc ||
- !(rel+1)->scattered || (rel+1)->type != 1 ||
- (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
- werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
- goto bad;
- }
- rp->siz = rel->length;
- rp->off = rel->addr;
-
- // NOTE(rsc): I haven't worked out why (really when)
- // we should ignore the addend on a
- // scattered relocation, but it seems that the
- // common case is we ignore it.
- // It's likely that this is not strictly correct
- // and that the math should look something
- // like the non-scattered case below.
- rp->add = 0;
-
- // want to make it pc-relative aka relative to rp->off+4
- // but the scatter asks for relative to off = (rel+1)->value - sect->addr.
- // adjust rp->add accordingly.
- rp->type = D_PCREL;
- rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
-
- // now consider the desired symbol.
- // find the section where it lives.
- for(k=0; k<c->seg.nsect; k++) {
- ks = &c->seg.sect[k];
- if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
- goto foundk;
- }
- werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
- goto bad;
- foundk:
- if(ks->sym != S) {
- rp->sym = ks->sym;
- rp->add += rel->value - ks->addr;
- } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
- // handle reference to __IMPORT/__pointers.
- // how much worse can this get?
- // why are we supporting 386 on the mac anyway?
- rp->type = 512 + MACHO_FAKE_GOTPCREL;
- // figure out which pointer this is a reference to.
- k = ks->res1 + (rel->value - ks->addr) / 4;
- // load indirect table for __pointers
- // fetch symbol number
- if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
- werrstr("invalid scattered relocation: indirect symbol reference out of range");
- goto bad;
- }
- k = dsymtab->indir[k];
- if(k < 0 || k >= symtab->nsym) {
- werrstr("invalid scattered relocation: symbol reference out of range");
- goto bad;
- }
- rp->sym = symtab->sym[k].sym;
- } else {
- werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
- goto bad;
- }
- rp++;
- // skip #1 of 2 rel; continue skips #2 of 2.
- rel++;
- j++;
- continue;
- }
-
- rp->siz = rel->length;
- rp->type = 512 + (rel->type<<1) + rel->pcrel;
- rp->off = rel->addr;
-
- // 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.
- if(rel->pcrel && thechar == '8')
- rp->add += rp->off+rp->siz;
- if(!rel->extrn) {
- if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
- werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
- goto bad;
- }
- rp->sym = c->seg.sect[rel->symnum-1].sym;
- if(rp->sym == nil) {
- werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
- goto bad;
- }
- // References to symbols in other sections
- // include that information in the addend.
- // We only care about the delta from the
- // section base.
- if(thechar == '8')
- rp->add -= c->seg.sect[rel->symnum-1].addr;
- } else {
- if(rel->symnum >= symtab->nsym) {
- werrstr("invalid relocation: symbol reference out of range");
- goto bad;
- }
- rp->sym = symtab->sym[rel->symnum].sym;
- }
- rp++;
- }
- qsort(r, rp - r, sizeof r[0], rbyoff);
- s->r = r;
- s->nr = rp - r;
- }
- return;
-
-bad:
- diag("%s: malformed mach-o file: %r", pn);
-}