From 7663ffcae641dbf06b9d5321c9afbad4fc73e336 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 7 Mar 2013 19:57:25 -0800 Subject: [PATCH] cmd/ld: steps toward 386 host linking - Introduce MaxAlign constant and use in data layout and ELF section header. - Allow up to 16-byte alignment for large objects (will help Keith's hash changes). - Emit ELF symbol for .rathole (global /dev/null used by 8c). - Invoke gcc with -m32/-m64 as appropriate. - Don't invoke gcc if writing the .o file failed. R=golang-dev, iant CC=golang-dev https://golang.org/cl/7563045 --- src/cmd/5l/l.h | 1 + src/cmd/6l/l.h | 1 + src/cmd/8l/l.h | 1 + src/cmd/8l/obj.c | 4 ++ src/cmd/ld/data.c | 139 +++++++++++++++++++++++++--------------------- src/cmd/ld/elf.c | 2 +- src/cmd/ld/lib.c | 13 ++++- src/cmd/ld/lib.h | 1 + 8 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 059e269a91..0b31b07ab6 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -38,6 +38,7 @@ enum thechar = '5', PtrSize = 4, IntSize = 4, + MaxAlign = 8, // max data alignment FuncAlign = 4 // single-instruction alignment }; diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 1790f718a9..a06dff8c09 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -42,6 +42,7 @@ enum thechar = '6', PtrSize = 8, IntSize = 8, + MaxAlign = 32, // max data alignment // Loop alignment constants: // want to align loop entry to LoopAlign-byte boundary, diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 062dc05662..f6de746466 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -42,6 +42,7 @@ enum thechar = '8', PtrSize = 4, IntSize = 4, + MaxAlign = 32, // max data alignment FuncAlign = 16 }; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index f06bc5d9dc..8144dfadd0 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -130,6 +130,10 @@ main(int argc, char *argv[]) flagparse(&argc, &argv, usage); + // TODO: link mode flag instead of isobj + if(isobj) + linkmode = LinkExternal; + if(argc != 1) usage(); diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c index b344abd9b0..3cdef28771 100644 --- a/src/cmd/ld/data.c +++ b/src/cmd/ld/data.c @@ -875,36 +875,38 @@ dosymtype(void) } static int32 -alignsymsize(int32 s) +symalign(Sym *s) { - if(s >= 8) - s = rnd(s, 8); - else if(s >= PtrSize) - s = rnd(s, PtrSize); - else if(s > 2) - s = rnd(s, 4); - return s; + int32 align; + + align = MaxAlign; + while(align > s->size && align > 1) + align >>= 1; + if(align < s->align) + align = s->align; + return align; } - + static int32 aligndatsize(int32 datsize, Sym *s) { - int32 t; + return rnd(datsize, symalign(s)); +} - if(s->align != 0) { - datsize = rnd(datsize, s->align); - } else { - t = alignsymsize(s->size); - if(t & 1) { - ; - } else if(t & 2) - datsize = rnd(datsize, 2); - else if(t & 4) - datsize = rnd(datsize, 4); - else - datsize = rnd(datsize, 8); +// maxalign returns the maximum required alignment for +// the list of symbols s; the list stops when s->type exceeds type. +static int32 +maxalign(Sym *s, int type) +{ + int32 align, max; + + max = 0; + for(; s != S && s->type <= type; s = s->next) { + align = symalign(s); + if(max < align) + max = align; } - return datsize; + return max; } static void @@ -938,7 +940,7 @@ gcaddsym(Sym *gc, Sym *s, int32 off) void dodata(void) { - int32 t, datsize; + int32 datsize; Section *sect; Sym *s, *last, **l; Sym *gcdata1, *gcbss1; @@ -1026,52 +1028,54 @@ dodata(void) datsize = 0; for(; s != nil && s->type < SNOPTRDATA; s = s->next) { sect = addsection(&segdata, s->name, 06); - if(s->align != 0) - datsize = rnd(datsize, s->align); + sect->align = symalign(s); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SDATA; s->value = datsize; - datsize += rnd(s->size, PtrSize); + datsize += s->size; sect->len = datsize - sect->vaddr; } /* pointer-free data */ sect = addsection(&segdata, ".noptrdata", 06); + sect->align = maxalign(s, SDATARELRO-1); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("noptrdata", 0)->sect = sect; lookup("enoptrdata", 0)->sect = sect; for(; s != nil && s->type < SDATARELRO; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SDATA; - t = alignsymsize(s->size); - datsize = aligndatsize(datsize, s); s->value = datsize; - datsize += t; + datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* dynamic relocated rodata */ if(flag_shared) { sect = addsection(&segdata, ".data.rel.ro", 06); + sect->align = maxalign(s, SDATARELRO); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("datarelro", 0)->sect = sect; lookup("edatarelro", 0)->sect = sect; for(; s != nil && s->type == SDATARELRO; s = s->next) { - if(s->align != 0) - datsize = rnd(datsize, s->align); + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SDATA; s->value = datsize; - datsize += rnd(s->size, PtrSize); + datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); } /* data */ sect = addsection(&segdata, ".data", 06); + sect->align = maxalign(s, SBSS-1); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("data", 0)->sect = sect; lookup("edata", 0)->sect = sect; @@ -1082,39 +1086,39 @@ dodata(void) } s->sect = sect; s->type = SDATA; - t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcdata1, s, datsize - sect->vaddr); // gc - datsize += t; + datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); adduintxx(gcdata1, GC_END, PtrSize); setuintxx(gcdata1, 0, sect->len, PtrSize); /* bss */ sect = addsection(&segdata, ".bss", 06); + sect->align = maxalign(s, SNOPTRBSS-1); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("bss", 0)->sect = sect; lookup("ebss", 0)->sect = sect; for(; s != nil && s->type < SNOPTRBSS; s = s->next) { s->sect = sect; - t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); s->value = datsize; gcaddsym(gcbss1, s, datsize - sect->vaddr); // gc - datsize += t; + datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); adduintxx(gcbss1, GC_END, PtrSize); setuintxx(gcbss1, 0, sect->len, PtrSize); /* pointer-free bss */ sect = addsection(&segdata, ".noptrbss", 06); + sect->align = maxalign(s, SNOPTRBSS); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("noptrbss", 0)->sect = sect; lookup("enoptrbss", 0)->sect = sect; @@ -1123,11 +1127,10 @@ dodata(void) cursym = s; diag("unexpected symbol type %d", s->type); } - s->sect = sect; - t = alignsymsize(s->size); datsize = aligndatsize(datsize, s); + s->sect = sect; s->value = datsize; - datsize += t; + datsize += s->size; } sect->len = datsize - sect->vaddr; lookup("end", 0)->sect = sect; @@ -1135,103 +1138,112 @@ dodata(void) /* we finished segdata, begin segtext */ /* read-only data */ + s = datap; sect = addsection(&segtext, ".rodata", 04); + sect->align = maxalign(s, STYPELINK-1); sect->vaddr = 0; lookup("rodata", 0)->sect = sect; lookup("erodata", 0)->sect = sect; datsize = 0; - s = datap; for(; s != nil && s->type < STYPELINK; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; - if(s->align != 0) - datsize = rnd(datsize, s->align); s->type = SRODATA; s->value = datsize; - datsize += rnd(s->size, PtrSize); + datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* type */ sect = addsection(&segtext, ".typelink", 04); + sect->align = maxalign(s, STYPELINK); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("typelink", 0)->sect = sect; lookup("etypelink", 0)->sect = sect; for(; s != nil && s->type == STYPELINK; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* gcdata */ sect = addsection(&segtext, ".gcdata", 04); + sect->align = maxalign(s, SGCDATA); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("gcdata", 0)->sect = sect; lookup("egcdata", 0)->sect = sect; for(; s != nil && s->type == SGCDATA; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* gcbss */ sect = addsection(&segtext, ".gcbss", 04); + sect->align = maxalign(s, SGCBSS); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("gcbss", 0)->sect = sect; lookup("egcbss", 0)->sect = sect; for(; s != nil && s->type == SGCBSS; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* gosymtab */ sect = addsection(&segtext, ".gosymtab", 04); + sect->align = maxalign(s, SPCLNTAB-1); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("symtab", 0)->sect = sect; lookup("esymtab", 0)->sect = sect; for(; s != nil && s->type < SPCLNTAB; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* gopclntab */ sect = addsection(&segtext, ".gopclntab", 04); + sect->align = maxalign(s, SELFROSECT-1); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; lookup("pclntab", 0)->sect = sect; lookup("epclntab", 0)->sect = sect; for(; s != nil && s->type < SELFROSECT; s = s->next) { + datsize = aligndatsize(datsize, s); s->sect = sect; s->type = SRODATA; s->value = datsize; datsize += s->size; } sect->len = datsize - sect->vaddr; - datsize = rnd(datsize, PtrSize); /* read-only ELF sections */ for(; s != nil && s->type < SELFSECT; s = s->next) { sect = addsection(&segtext, s->name, 04); - if(s->align != 0) - datsize = rnd(datsize, s->align); + sect->align = symalign(s); + datsize = rnd(datsize, sect->align); sect->vaddr = datsize; s->sect = sect; s->type = SRODATA; s->value = datsize; - datsize += rnd(s->size, PtrSize); + datsize += s->size; sect->len = datsize - sect->vaddr; } } @@ -1251,6 +1263,7 @@ textaddress(void) // Could parallelize, by assigning to text // and then letting threads copy down, but probably not worth it. sect = segtext.sect; + sect->align = FuncAlign; lookup("text", 0)->sect = sect; lookup("etext", 0)->sect = sect; va = INITTEXT; @@ -1274,11 +1287,6 @@ textaddress(void) } va += sym->size; } - - // Align end of code so that rodata starts aligned. - // 128 bytes is likely overkill but definitely cheap. - va = rnd(va, 128); - sect->len = va - sect->vaddr; } @@ -1296,8 +1304,9 @@ address(void) segtext.vaddr = va; segtext.fileoff = HEADR; for(s=segtext.sect; s != nil; s=s->next) { + va = rnd(va, s->align); s->vaddr = va; - va += rnd(s->len, PtrSize); + va += s->len; } segtext.len = va - INITTEXT; segtext.filelen = segtext.len; @@ -1318,6 +1327,8 @@ address(void) noptrbss = nil; datarelro = nil; for(s=segdata.sect; s != nil; s=s->next) { + if(s->next) + s->len = s->next->vaddr - s->vaddr; s->vaddr = va; va += s->len; segdata.filelen += s->len; @@ -1333,7 +1344,7 @@ address(void) if(strcmp(s->name, ".data.rel.ro") == 0) datarelro = s; } - segdata.filelen -= bss->len + noptrbss->len; // deduct .bss + segdata.filelen = bss->vaddr - segdata.vaddr; text = segtext.sect; rodata = text->next; diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index 630906653e..0eb2fa531c 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -762,7 +762,7 @@ elfshbits(Section *sect) sh->flags |= SHF_WRITE; if(!isobj) sh->addr = sect->vaddr; - sh->addralign = PtrSize; + sh->addralign = sect->align; sh->size = sect->len; sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr; diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index db6b7761b7..99ff86aab9 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -598,7 +598,7 @@ hostlink(void) Biobuf *f; static char buf[64<<10]; - if(linkmode != LinkExternal) + if(linkmode != LinkExternal || nerrors > 0) return; argv = malloc((10+nhostobj+nldflag)*sizeof argv[0]); @@ -606,6 +606,14 @@ hostlink(void) // TODO: Add command-line flag to override gcc path and specify additional leading options. // TODO: Add command-line flag to specify additional trailing options. argv[argc++] = "gcc"; + switch(thechar){ + case '8': + argv[argc++] = "-m32"; + break; + case '6': + argv[argc++] = "-m64"; + break; + } if(!debug['s']) argv[argc++] = "-ggdb"; argv[argc++] = "-o"; @@ -1249,6 +1257,7 @@ addsection(Segment *seg, char *name, int rwx) sect->rwx = rwx; sect->name = name; sect->seg = seg; + sect->align = PtrSize; // everything is at least pointer-aligned *l = sect; return sect; } @@ -1781,7 +1790,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) put(s, s->name, 'T', s->value, s->size, s->version, 0); for(s=allsym; s!=S; s=s->allsym) { - if(s->hide || (s->name[0] == '.' && s->version == 0)) + if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0)) continue; switch(s->type&SMASK) { case SCONST: diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index 0b7e48c8a2..8b67932315 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -104,6 +104,7 @@ struct Segment struct Section { uchar rwx; + int32 align; char *name; uvlong vaddr; uvlong len; -- 2.48.1