summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/ld/data.c51
-rw-r--r--src/cmd/ld/ldelf.c49
-rw-r--r--src/cmd/ld/ldmacho.c35
-rw-r--r--src/cmd/ld/ldpe.c35
-rw-r--r--src/cmd/ld/lib.h3
-rw-r--r--src/pkg/runtime/symtab.c10
6 files changed, 128 insertions, 55 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 1e0bd2cd0..6c6b1be43 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -58,70 +58,73 @@ datcmp(Sym *s1, Sym *s2)
}
Sym*
-datsort(Sym *l)
+listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
{
Sym *l1, *l2, *le;
+ #define NEXT(l) (*(Sym**)((char*)(l)+off))
- if(l == 0 || l->next == 0)
+ if(l == 0 || NEXT(l) == 0)
return l;
l1 = l;
l2 = l;
for(;;) {
- l2 = l2->next;
+ l2 = NEXT(l2);
if(l2 == 0)
break;
- l2 = l2->next;
+ l2 = NEXT(l2);
if(l2 == 0)
break;
- l1 = l1->next;
+ l1 = NEXT(l1);
}
- l2 = l1->next;
- l1->next = 0;
- l1 = datsort(l);
- l2 = datsort(l2);
+ l2 = NEXT(l1);
+ NEXT(l1) = 0;
+ l1 = listsort(l, cmp, off);
+ l2 = listsort(l2, cmp, off);
/* set up lead element */
- if(datcmp(l1, l2) < 0) {
+ if(cmp(l1, l2) < 0) {
l = l1;
- l1 = l1->next;
+ l1 = NEXT(l1);
} else {
l = l2;
- l2 = l2->next;
+ l2 = NEXT(l2);
}
le = l;
for(;;) {
if(l1 == 0) {
while(l2) {
- le->next = l2;
+ NEXT(le) = l2;
le = l2;
- l2 = l2->next;
+ l2 = NEXT(l2);
}
- le->next = 0;
+ NEXT(le) = 0;
break;
}
if(l2 == 0) {
while(l1) {
- le->next = l1;
+ NEXT(le) = l1;
le = l1;
- l1 = l1->next;
+ l1 = NEXT(l1);
}
break;
}
- if(datcmp(l1, l2) < 0) {
- le->next = l1;
+ if(cmp(l1, l2) < 0) {
+ NEXT(le) = l1;
le = l1;
- l1 = l1->next;
+ l1 = NEXT(l1);
} else {
- le->next = l2;
+ NEXT(le) = l2;
le = l2;
- l2 = l2->next;
+ l2 = NEXT(l2);
}
}
- le->next = 0;
+ NEXT(le) = 0;
return l;
+
+ #undef NEXT
}
Reloc*
@@ -1010,7 +1013,7 @@ dodata(void)
s->type = SDATARELRO;
}
}
- datap = datsort(datap);
+ datap = listsort(datap, datcmp, offsetof(Sym, next));
/*
* allocate sections. list is sorted by type,
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
index 19c582b00..2bbf4f83e 100644
--- a/src/cmd/ld/ldelf.c
+++ b/src/cmd/ld/ldelf.c
@@ -311,6 +311,16 @@ static int map(ElfObj*, ElfSect*);
static int readsym(ElfObj*, int i, ElfSym*, int);
static int reltype(char*, int, uchar*);
+int
+valuecmp(Sym *a, Sym *b)
+{
+ if(a->value < b->value)
+ return -1;
+ if(a->value > b->value)
+ return +1;
+ return 0;
+}
+
void
ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
{
@@ -541,13 +551,6 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
}
s->size = sect->size;
s->align = sect->align;
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
sect->sym = s;
}
@@ -583,6 +586,12 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
continue;
}
s = sym.sym;
+ 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->sub = sect->sym->sub;
sect->sym->sub = s;
s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
@@ -611,7 +620,25 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
p->link = nil;
p->pc = pc++;
s->text = p;
-
+ }
+ }
+ }
+
+ // Sort outer lists by address, adding to textp.
+ // This keeps textp in increasing address order.
+ for(i=0; i<obj->nsect; i++) {
+ s = obj->sect[i].sym;
+ if(s == 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;
}
@@ -792,7 +819,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// set dupok generally. See http://codereview.appspot.com/5823055/
// comment #5 for details.
if(s && sym->other == 2) {
- s->type = SHIDDEN;
+ s->type |= SHIDDEN;
s->dupok = 1;
}
}
@@ -804,14 +831,14 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// and should only reference by its index, not name, so we
// don't bother to add them into hash table
s = newsym(sym->name, version);
- s->type = SHIDDEN;
+ s->type |= SHIDDEN;
}
break;
case ElfSymBindWeak:
if(needSym) {
s = newsym(sym->name, 0);
if(sym->other == 2)
- s->type = SHIDDEN;
+ s->type |= SHIDDEN;
}
break;
default:
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
index 3310903e1..41852f17c 100644
--- a/src/cmd/ld/ldmacho.c
+++ b/src/cmd/ld/ldmacho.c
@@ -593,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;
}
@@ -631,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;
@@ -661,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
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index 8923bc729..f41827bef 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -236,13 +236,6 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
s->p = sect->base;
s->np = sect->size;
s->size = sect->size;
- if(s->type == STEXT) {
- if(etextp)
- etextp->next = s;
- else
- textp = s;
- etextp = s;
- }
sect->sym = s;
if(strcmp(sect->name, ".rsrc") == 0)
setpersrc(sect->sym);
@@ -327,6 +320,12 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
s = sym->sym;
+ 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();
+ }
if(sym->sectnum == 0) {// extern
if(s->type == SDYNIMPORT)
s->plt = -2; // flag for dynimport in PE object files.
@@ -367,9 +366,27 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
p->link = nil;
p->pc = pc++;
s->text = p;
-
- etextp->next = s;
+ }
+ }
+
+ // Sort outer lists by address, adding to textp.
+ // This keeps textp in increasing address order.
+ for(i=0; i<obj->nsect; i++) {
+ s = obj->sect[i].sym;
+ if(s == 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;
+ }
}
}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index d2a8b6fbe..acfad9775 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -196,7 +196,6 @@ void deadcode(void);
Reloc* addrel(Sym*);
void codeblk(int32, int32);
void datblk(int32, int32);
-Sym* datsort(Sym*);
void reloc(void);
void relocsym(Sym*);
void savedata(Sym*, Prog*, char*);
@@ -238,6 +237,8 @@ void setpersrc(Sym*);
void doversion(void);
void usage(void);
void setinterp(char*);
+Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
+int valuecmp(Sym*, Sym*);
int pathchar(void);
void* mal(uint32);
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 248558685..d7221c476 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -195,12 +195,13 @@ static int32 nfname;
static uint32 funcinit;
static Lock funclock;
+static uintptr lastvalue;
static void
dofunc(Sym *sym)
{
Func *f;
-
+
switch(sym->symtype) {
case 't':
case 'T':
@@ -208,6 +209,11 @@ dofunc(Sym *sym)
case 'L':
if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
break;
+ if(sym->value < lastvalue) {
+ runtime·printf("symbols out of order: %p before %p\n", lastvalue, sym->value);
+ runtime·throw("malformed symbol table");
+ }
+ lastvalue = sym->value;
if(func == nil) {
nfunc++;
break;
@@ -544,6 +550,7 @@ buildfuncs(void)
// count funcs, fnames
nfunc = 0;
nfname = 0;
+ lastvalue = 0;
walksymtab(dofunc);
// Initialize tables.
@@ -553,6 +560,7 @@ buildfuncs(void)
func[nfunc].entry = (uint64)etext;
fname = runtime·mallocgc(nfname*sizeof fname[0], FlagNoPointers, 0, 1);
nfunc = 0;
+ lastvalue = 0;
walksymtab(dofunc);
// split pc/ln table by func