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.c66
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;