Commit 7663ffca authored by Russ Cox's avatar Russ Cox

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
parent dfc22e29
......@@ -38,6 +38,7 @@ enum
thechar = '5',
PtrSize = 4,
IntSize = 4,
MaxAlign = 8, // max data alignment
FuncAlign = 4 // single-instruction alignment
};
......
......@@ -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,
......
......@@ -42,6 +42,7 @@ enum
thechar = '8',
PtrSize = 4,
IntSize = 4,
MaxAlign = 32, // max data alignment
FuncAlign = 16
};
......
......@@ -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();
......
......@@ -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;
......
......@@ -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;
......
......@@ -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:
......
......@@ -104,6 +104,7 @@ struct Segment
struct Section
{
uchar rwx;
int32 align;
char *name;
uvlong vaddr;
uvlong len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment