aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/ld/data.c1
-rw-r--r--src/cmd/ld/lib.c34
-rw-r--r--src/cmd/ld/symtab.c108
3 files changed, 94 insertions, 49 deletions
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 99385fdcc2..e4d16fdc1f 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -1163,7 +1163,6 @@ dodata(void)
sect->vaddr = 0;
lookup("rodata", 0)->sect = sect;
lookup("erodata", 0)->sect = sect;
- lookup("reloffset", 0)->sect = sect;
datsize = 0;
s = datap;
for(; s != nil && s->type < STYPELINK; s = s->next) {
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 4f0b87466b..26fa4f2ac7 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -1564,6 +1564,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
Auto *a;
Sym *s;
+ int32 off;
// These symbols won't show up in the first loop below because we
// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
@@ -1627,16 +1628,37 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
/* frame, locals, args, auto and param after */
- put(nil, ".frame", 'm', s->text->to.offset+PtrSize, 0, 0, 0);
+ put(nil, ".frame", 'm', (uint32)s->text->to.offset+PtrSize, 0, 0, 0);
put(nil, ".locals", 'm', s->locals, 0, 0, 0);
put(nil, ".args", 'm', s->args, 0, 0, 0);
- for(a=s->autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
+ for(a=s->autom; a; a=a->link) {
+ // Emit a or p according to actual offset, even if label is wrong.
+ // This avoids negative offsets, which cannot be encoded.
+ if(a->type != D_AUTO && a->type != D_PARAM)
+ continue;
+
+ // compute offset relative to FP
if(a->type == D_PARAM)
- put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ off = a->aoffset;
+ else
+ off = a->aoffset - PtrSize;
+
+ // FP
+ if(off >= 0) {
+ put(nil, a->asym->name, 'p', off, 0, 0, a->gotype);
+ continue;
+ }
+
+ // SP
+ if(off <= -PtrSize) {
+ put(nil, a->asym->name, 'a', -(off+PtrSize), 0, 0, a->gotype);
+ continue;
+ }
+
+ // Otherwise, off is addressing the saved program counter.
+ // Something underhanded is going on. Say nothing.
+ }
}
if(debug['v'] || debug['n'])
Bprint(&bso, "symsize = %ud\n", symsize);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index 42e367291d..144f82a3ba 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -295,41 +295,76 @@ vputl(uint64 v)
lputl(v >> 32);
}
+// Emit symbol table entry.
+// The table format is described at the top of ../../pkg/runtime/symtab.c.
void
putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
{
- int i, f, l;
+ int i, f, c;
+ vlong v1;
Reloc *rel;
USED(size);
- if(t == 'f')
- name++;
- l = 4;
-// if(!debug['8'])
-// l = 8;
+
+ // type byte
+ if('A' <= t && t <= 'Z')
+ c = t - 'A';
+ else if('a' <= t && t <= 'z')
+ c = t - 'a' + 26;
+ else {
+ diag("invalid symbol table type %c", t);
+ errorexit();
+ return;
+ }
+
+ if(s != nil)
+ c |= 0x40; // wide value
+ if(typ != nil)
+ c |= 0x80; // has go type
+ scput(c);
+
+ // value
if(s != nil) {
+ // full width
rel = addrel(symt);
- rel->siz = l;
+ rel->siz = PtrSize;
rel->sym = s;
rel->type = D_ADDR;
rel->off = symt->size;
- v = 0;
- }
-
- if(l == 8) {
- if(slput == slputl) {
- slputl(v);
- slputl(v>>32);
- } else {
- slputb(v>>32);
- slputb(v);
+ if(PtrSize == 8)
+ slput(0);
+ slput(0);
+ } else {
+ // varint
+ if(v < 0) {
+ diag("negative value in symbol table: %s %lld", name, v);
+ errorexit();
}
- } else
- slput(v);
+ v1 = v;
+ while(v1 >= 0x80) {
+ scput(v1 | 0x80);
+ v1 >>= 7;
+ }
+ scput(v1);
+ }
- if(ver)
- t += 'a' - 'A';
- scput(t+0x80); /* 0x80 is variable length */
+ // go type if present
+ if(typ != nil) {
+ if(!typ->reachable)
+ diag("unreachable type %s", typ->name);
+ rel = addrel(symt);
+ rel->siz = PtrSize;
+ rel->sym = typ;
+ rel->type = D_ADDR;
+ rel->off = symt->size;
+ if(PtrSize == 8)
+ slput(0);
+ slput(0);
+ }
+
+ // name
+ if(t == 'f')
+ name++;
if(t == 'Z' || t == 'z') {
scput(name[0]);
@@ -339,24 +374,11 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
}
scput(0);
scput(0);
- }
- else {
+ } else {
for(i=0; name[i]; i++)
scput(name[i]);
scput(0);
}
- if(typ) {
- if(!typ->reachable)
- diag("unreachable type %s", typ->name);
- rel = addrel(symt);
- rel->siz = l;
- rel->sym = typ;
- rel->type = D_ADDR;
- rel->off = symt->size;
- }
- if(l == 8)
- slput(0);
- slput(0);
if(debug['n']) {
if(t == 'z' || t == 'Z') {
@@ -389,7 +411,6 @@ symtab(void)
xdefine("etypelink", SRODATA, 0);
xdefine("rodata", SRODATA, 0);
xdefine("erodata", SRODATA, 0);
- xdefine("reloffset", SRODATA, 0);
if(flag_shared) {
xdefine("datarelro", SDATARELRO, 0);
xdefine("edatarelro", SDATARELRO, 0);
@@ -464,17 +485,20 @@ symtab(void)
case '5':
case '6':
case '8':
- // magic entry to denote little-endian symbol table
- slputl(0xfffffffe);
- scput(0);
- scput(0);
+ // little-endian symbol table
slput = slputl;
break;
case 'v':
- // big-endian (in case one comes along)
+ // big-endian symbol table
slput = slputb;
break;
}
+ // new symbol table header.
+ slput(0xfffffffd);
+ scput(0);
+ scput(0);
+ scput(0);
+ scput(PtrSize);
genasmsym(putsymb);
}