diff options
Diffstat (limited to 'src/cmd/ld/ldmacho.c')
-rw-r--r-- | src/cmd/ld/ldmacho.c | 66 |
1 files changed, 48 insertions, 18 deletions
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c index 388848767..41852f17c 100644 --- a/src/cmd/ld/ldmacho.c +++ b/src/cmd/ld/ldmacho.c @@ -440,7 +440,6 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) Reloc *r, *rp; char *name; - USED(pkg); version++; base = Boffset(f); if(Bread(f, hdr, sizeof hdr) != sizeof hdr) @@ -566,16 +565,21 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) continue; if(strcmp(sect->name, "__eh_frame") == 0) continue; - name = smprint("%s(%s/%s)", pn, sect->segname, sect->name); + name = smprint("%s(%s/%s)", pkg, 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((sect->flags & 0xff) == 1) // S_ZEROFILL + s->p = mal(s->size); + else { + s->p = dat + sect->addr - c->seg.vmaddr; + } if(strcmp(sect->segname, "__TEXT") == 0) { if(strcmp(sect->name, "__text") == 0) @@ -589,13 +593,6 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) } else s->type = SDATA; } - if(s->type == STEXT) { - if(etextp) - etextp->next = s; - else - textp = s; - etextp = s; - } sect->sym = s; } @@ -627,6 +624,12 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) werrstr("reference to invalid section %s/%s", sect->segname, sect->name); continue; } + if(s->outer != S) { + if(s->dupok) + continue; + diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name); + errorexit(); + } s->type = outer->type | SSUB; s->sub = outer->sub; outer->sub = s; @@ -657,11 +660,29 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) p->link = nil; p->pc = pc++; s->text = p; + } + sym->sym = s; + } - etextp->next = s; + // Sort outer lists by address, adding to textp. + // This keeps textp in increasing address order. + for(i=0; i<c->seg.nsect; i++) { + sect = &c->seg.sect[i]; + if((s = sect->sym) == S) + continue; + if(s->sub) + s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub)); + if(s->type == STEXT) { + if(etextp) + etextp->next = s; + else + textp = s; etextp = s; + for(s = s->sub; s != S; s = s->sub) { + etextp->next = s; + etextp = s; + } } - sym->sym = s; } // load relocations @@ -680,19 +701,28 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn) int k; MachoSect *ks; - if(thechar != '8') + if(thechar != '8') { + // mach-o only uses scattered relocation on 32-bit platforms diag("unexpected scattered relocation"); + continue; + } - // on 386, rewrite scattered 4/1 relocation into - // the pseudo-pc-relative reference that it is. + // on 386, rewrite scattered 4/1 relocation and some + // scattered 2/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) { + if(j+1 >= sect->nreloc) { + werrstr("unsupported scattered relocation %d", (int)rel->type); + goto bad; + } + if(!(rel+1)->scattered || (rel+1)->type != 1 || + (rel->type != 4 && rel->type != 2) || + (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; |