diff options
Diffstat (limited to 'src/cmd')
48 files changed, 812 insertions, 734 deletions
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile index 6873fbc68..b47014a4e 100644 --- a/src/cmd/5g/Makefile +++ b/src/cmd/5g/Makefile @@ -15,16 +15,17 @@ HFILES=\ OFILES=\ ../5l/enam.$O\ - list.$O\ - galign.$O\ - gobj.$O\ - ggen.$O\ - gsubr.$O\ cgen.$O\ cgen64.$O\ cplx.$O\ - reg.$O\ + galign.$O\ + ggen.$O\ + gobj.$O\ + gsubr.$O\ + list.$O\ peep.$O\ + pgen.$O\ + reg.$O\ LIB=\ ../gc/gc.a\ diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c index 4e5f7ebcd..76e2707fa 100644 --- a/src/cmd/5g/cgen.c +++ b/src/cmd/5g/cgen.c @@ -1190,7 +1190,8 @@ void sgen(Node *n, Node *res, int32 w) { Node dst, src, tmp, nend; - int32 c, q, odst, osrc; + int32 c, odst, osrc; + int dir, align, op; Prog *p, *ploop; if(debug['g']) { @@ -1200,17 +1201,39 @@ sgen(Node *n, Node *res, int32 w) } if(w == 0) return; - if(n->ullman >= UINF && res->ullman >= UINF) { - fatal("sgen UINF"); - } - if(w < 0) fatal("sgen copy %d", w); + if(n->ullman >= UINF && res->ullman >= UINF) + fatal("sgen UINF"); + if(n->type == T) + fatal("sgen: missing type"); + + // determine alignment. + // want to avoid unaligned access, so have to use + // smaller operations for less aligned types. + // for example moving [4]byte must use 4 MOVB not 1 MOVW. + align = n->type->align; + op = 0; + switch(align) { + default: + fatal("sgen: invalid alignment %d for %T", align, n->type); + case 1: + op = AMOVB; + break; + case 2: + op = AMOVH; + break; + case 4: + op = AMOVW; + break; + } + if(w%align) + fatal("sgen: unaligned size %d (align=%d) for %T", w, align, n->type); + c = w / align; // offset on the stack osrc = stkof(n); odst = stkof(res); - if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { // osrc and odst both on stack, and at least one is in // an unknown position. Could generate code to test @@ -1221,12 +1244,15 @@ sgen(Node *n, Node *res, int32 w) sgen(&tmp, res, w); return; } - - if(osrc % 4 != 0 || odst %4 != 0) - fatal("sgen: non word(4) aligned offset src %d or dst %d", osrc, odst); + if(osrc%align != 0 || odst%align != 0) + fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); + // if we are copying forward on the stack and + // the src and dst overlap, then reverse direction + dir = align; + if(osrc < odst && odst < osrc+w) + dir = -dir; regalloc(&dst, types[tptr], res); - if(n->ullman >= res->ullman) { agen(n, &dst); // temporarily use dst regalloc(&src, types[tptr], N); @@ -1240,141 +1266,64 @@ sgen(Node *n, Node *res, int32 w) regalloc(&tmp, types[TUINT32], N); - c = w % 4; // bytes - q = w / 4; // quads - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - if(osrc < odst && odst < osrc+w) { - if(c != 0) - fatal("sgen: reverse character copy not implemented"); - if(q >= 4) { - regalloc(&nend, types[TUINT32], N); - // set up end marker to 4 bytes before source - p = gins(AMOVW, &src, &nend); - p->from.type = D_CONST; - p->from.offset = -4; - - // move src and dest to the end of block - p = gins(AMOVW, &src, &src); - p->from.type = D_CONST; - p->from.offset = (q-1)*4; - - p = gins(AMOVW, &dst, &dst); - p->from.type = D_CONST; - p->from.offset = (q-1)*4; - - p = gins(AMOVW, &src, &tmp); - p->from.type = D_OREG; - p->from.offset = -4; - p->scond |= C_PBIT; - ploop = p; + // set up end marker + memset(&nend, 0, sizeof nend); + if(c >= 4) { + regalloc(&nend, types[TUINT32], N); - p = gins(AMOVW, &tmp, &dst); - p->to.type = D_OREG; - p->to.offset = -4; - p->scond |= C_PBIT; - - p = gins(ACMP, &src, N); - raddr(&nend, p); + p = gins(AMOVW, &src, &nend); + p->from.type = D_CONST; + if(dir < 0) + p->from.offset = dir; + else + p->from.offset = w; + } - patch(gbranch(ABNE, T), ploop); + // move src and dest to the end of block if necessary + if(dir < 0) { + p = gins(AMOVW, &src, &src); + p->from.type = D_CONST; + p->from.offset = w + dir; - regfree(&nend); - } else { - // move src and dest to the end of block - p = gins(AMOVW, &src, &src); - p->from.type = D_CONST; - p->from.offset = (q-1)*4; - - p = gins(AMOVW, &dst, &dst); - p->from.type = D_CONST; - p->from.offset = (q-1)*4; - - while(q > 0) { - p = gins(AMOVW, &src, &tmp); - p->from.type = D_OREG; - p->from.offset = -4; - p->scond |= C_PBIT; - - p = gins(AMOVW, &tmp, &dst); - p->to.type = D_OREG; - p->to.offset = -4; - p->scond |= C_PBIT; - - q--; - } - } + p = gins(AMOVW, &dst, &dst); + p->from.type = D_CONST; + p->from.offset = w + dir; + } + + // move + if(c >= 4) { + p = gins(op, &src, &tmp); + p->from.type = D_OREG; + p->from.offset = dir; + p->scond |= C_PBIT; + ploop = p; + + p = gins(op, &tmp, &dst); + p->to.type = D_OREG; + p->to.offset = dir; + p->scond |= C_PBIT; + + p = gins(ACMP, &src, N); + raddr(&nend, p); + + patch(gbranch(ABNE, T), ploop); + regfree(&nend); } else { - // normal direction - if(q >= 4) { - regalloc(&nend, types[TUINT32], N); - p = gins(AMOVW, &src, &nend); - p->from.type = D_CONST; - p->from.offset = q*4; - - p = gins(AMOVW, &src, &tmp); + while(c-- > 0) { + p = gins(op, &src, &tmp); p->from.type = D_OREG; - p->from.offset = 4; + p->from.offset = dir; p->scond |= C_PBIT; ploop = p; - - p = gins(AMOVW, &tmp, &dst); + + p = gins(op, &tmp, &dst); p->to.type = D_OREG; - p->to.offset = 4; + p->to.offset = dir; p->scond |= C_PBIT; - - p = gins(ACMP, &src, N); - raddr(&nend, p); - - patch(gbranch(ABNE, T), ploop); - - regfree(&nend); - } else - while(q > 0) { - p = gins(AMOVW, &src, &tmp); - p->from.type = D_OREG; - p->from.offset = 4; - p->scond |= C_PBIT; - - p = gins(AMOVW, &tmp, &dst); - p->to.type = D_OREG; - p->to.offset = 4; - p->scond |= C_PBIT; - - q--; - } - - if (c != 0) { - // MOVW (src), tmp - p = gins(AMOVW, &src, &tmp); - p->from.type = D_OREG; - - // MOVW tmp<<((4-c)*8),src - gshift(AMOVW, &tmp, SHIFT_LL, ((4-c)*8), &src); - - // MOVW src>>((4-c)*8),src - gshift(AMOVW, &src, SHIFT_LR, ((4-c)*8), &src); - - // MOVW (dst), tmp - p = gins(AMOVW, &dst, &tmp); - p->from.type = D_OREG; - - // MOVW tmp>>(c*8),tmp - gshift(AMOVW, &tmp, SHIFT_LR, (c*8), &tmp); - - // MOVW tmp<<(c*8),tmp - gshift(AMOVW, &tmp, SHIFT_LL, c*8, &tmp); - - // ORR src, tmp - gins(AORR, &src, &tmp); - - // MOVW tmp, (dst) - p = gins(AMOVW, &tmp, &dst); - p->to.type = D_OREG; } } - regfree(&dst); + + regfree(&dst); regfree(&src); regfree(&tmp); } diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c index 7197709d4..0bc1b38fc 100644 --- a/src/cmd/5g/ggen.c +++ b/src/cmd/5g/ggen.c @@ -7,107 +7,9 @@ #include "gg.h" #include "opt.h" -static Prog *pret; - void -compile(Node *fn) +defframe(Prog *ptxt) { - Plist *pl; - Node nod1; - Prog *ptxt; - int32 lno; - Type *t; - Iter save; - - if(newproc == N) { - newproc = sysfunc("newproc"); - deferproc = sysfunc("deferproc"); - deferreturn = sysfunc("deferreturn"); - panicindex = sysfunc("panicindex"); - panicslice = sysfunc("panicslice"); - throwreturn = sysfunc("throwreturn"); - } - - if(fn->nbody == nil) - return; - - // set up domain for labels - clearlabels(); - - lno = setlineno(fn); - - curfn = fn; - dowidth(curfn->type); - - if(curfn->type->outnamed) { - // add clearing of the output parameters - t = structfirst(&save, getoutarg(curfn->type)); - while(t != T) { - if(t->nname != N) - curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody); - t = structnext(&save); - } - } - - hasdefer = 0; - walk(curfn); - if(nerrors != 0 || isblank(curfn->nname)) - goto ret; - - allocparams(); - - continpc = P; - breakpc = P; - - pl = newplist(); - pl->name = curfn->nname; - - setlineno(curfn); - - nodconst(&nod1, types[TINT32], 0); - ptxt = gins(ATEXT, curfn->nname, &nod1); - afunclit(&ptxt->from); - - ginit(); - genlist(curfn->enter); - - pret = nil; - if(hasdefer || curfn->exit) { - Prog *p1; - - p1 = gjmp(nil); - pret = gjmp(nil); - patch(p1, pc); - } - - genlist(curfn->nbody); - gclean(); - checklabels(); - if(nerrors != 0) - goto ret; - - if(curfn->type->outtuple != 0) - ginscall(throwreturn, 0); - - if(pret) - patch(pret, pc); - ginit(); - if(hasdefer) - ginscall(deferreturn, 0); - if(curfn->exit) - genlist(curfn->exit); - gclean(); - if(nerrors != 0) - goto ret; - if(curfn->endlineno) - lineno = curfn->endlineno; - pc->as = ARET; // overwrite AEND - pc->lineno = lineno; - - if(!debug['N'] || debug['R'] || debug['P']) { - regopt(ptxt); - } - // fill in argument size ptxt->to.type = D_CONST2; ptxt->reg = 0; // flags @@ -118,12 +20,6 @@ compile(Node *fn) maxstksize = stksize; ptxt->to.offset = rnd(maxstksize+maxarg, widthptr); maxstksize = 0; - - if(debug['f']) - frame(0); - -ret: - lineno = lno; } /* @@ -197,7 +93,7 @@ ginscall(Node *f, int proc) nodconst(&con, types[TINT32], 0); p = gins(ACMP, &con, N); p->reg = 0; - patch(gbranch(ABNE, T), pret); + patch(gbranch(ABNE, T), retpc); } break; } @@ -401,7 +297,7 @@ cgen_ret(Node *n) { genlist(n->list); // copy out args if(hasdefer || curfn->exit) - gjmp(pret); + gjmp(retpc); else gins(ARET, N, N); } diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 9e9c2c1eb..81c08e353 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -1977,3 +1977,9 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) Bprint(&bso, "symsize = %ud\n", symsize); Bflush(&bso); } + +void +setpersrc(Sym *s) +{ + USED(s); +} diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile index 023f5d111..64fa15399 100644 --- a/src/cmd/6g/Makefile +++ b/src/cmd/6g/Makefile @@ -14,16 +14,17 @@ HFILES=\ opt.h\ OFILES=\ - list.$O\ - gobj.$O\ - galign.$O\ - ggen.$O\ + ../6l/enam.$O\ cgen.$O\ cplx.$O\ + galign.$O\ + ggen.$O\ + gobj.$O\ gsubr.$O\ + list.$O\ peep.$O\ + pgen.$O\ reg.$O\ - ../6l/enam.$O\ LIB=\ ../gc/gc.a\ diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c index ce66b43f0..5260335df 100644 --- a/src/cmd/6g/ggen.c +++ b/src/cmd/6g/ggen.c @@ -7,121 +7,18 @@ #include "gg.h" #include "opt.h" -static Prog *pret; - void -compile(Node *fn) +defframe(Prog *ptxt) { - Plist *pl; - Node nod1; - Prog *ptxt; - int32 lno; - Type *t; - Iter save; - - if(newproc == N) { - newproc = sysfunc("newproc"); - deferproc = sysfunc("deferproc"); - deferreturn = sysfunc("deferreturn"); - panicindex = sysfunc("panicindex"); - panicslice = sysfunc("panicslice"); - throwreturn = sysfunc("throwreturn"); - } - - if(fn->nbody == nil) - return; - - // set up domain for labels - clearlabels(); - - lno = setlineno(fn); - - curfn = fn; - dowidth(curfn->type); - - if(curfn->type->outnamed) { - // add clearing of the output parameters - t = structfirst(&save, getoutarg(curfn->type)); - while(t != T) { - if(t->nname != N) - curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody); - t = structnext(&save); - } - } - - hasdefer = 0; - walk(curfn); - if(nerrors != 0 || isblank(curfn->nname)) - goto ret; - - allocparams(); - - continpc = P; - breakpc = P; - - pl = newplist(); - pl->name = curfn->nname; - - setlineno(curfn); - - nodconst(&nod1, types[TINT32], 0); - ptxt = gins(ATEXT, curfn->nname, &nod1); - afunclit(&ptxt->from); - - ginit(); - genlist(curfn->enter); - - pret = nil; - if(hasdefer || curfn->exit) { - Prog *p1; - - p1 = gjmp(nil); - pret = gjmp(nil); - patch(p1, pc); - } - - genlist(curfn->nbody); - gclean(); - checklabels(); - if(nerrors != 0) - goto ret; - if(curfn->endlineno) - lineno = curfn->endlineno; - - if(curfn->type->outtuple != 0) - ginscall(throwreturn, 0); - - if(pret) - patch(pret, pc); - ginit(); - if(hasdefer) - ginscall(deferreturn, 0); - if(curfn->exit) - genlist(curfn->exit); - gclean(); - if(nerrors != 0) - goto ret; - pc->as = ARET; // overwrite AEND - pc->lineno = lineno; - - if(!debug['N'] || debug['R'] || debug['P']) { - regopt(ptxt); - } - // fill in argument size ptxt->to.offset = rnd(curfn->type->argwid, widthptr); // fill in final stack size ptxt->to.offset <<= 32; ptxt->to.offset |= rnd(stksize+maxarg, widthptr); - - if(debug['f']) - frame(0); - -ret: - lineno = lno; } + /* * generate: * call f @@ -163,7 +60,7 @@ ginscall(Node *f, int proc) if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTQ, ®, ®); - patch(gbranch(AJNE, T), pret); + patch(gbranch(AJNE, T), retpc); } break; } @@ -355,7 +252,7 @@ cgen_ret(Node *n) { genlist(n->list); // copy out args if(hasdefer || curfn->exit) - gjmp(pret); + gjmp(retpc); else gins(ARET, N, N); } diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 6dffa20f2..320f4c9e9 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -828,6 +828,7 @@ asmb(void) dwarfemitdebugsections(); } break; + case Hdarwin: case Hwindows: seek(cout, symo, 0); if(debug['v']) diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index d53814a74..e3191bb4d 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -177,7 +177,7 @@ main(int argc, char *argv[]) */ tlsoffset = 0x8a0; machoinit(); - HEADR = MACHORESERVE; + HEADR = INITIAL_MACHO_HEADR; if(INITRND == -1) INITRND = 4096; if(INITTEXT == -1) diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile index 09cf8d4e3..b459782a3 100644 --- a/src/cmd/8g/Makefile +++ b/src/cmd/8g/Makefile @@ -15,15 +15,16 @@ HFILES=\ OFILES=\ ../8l/enam.$O\ - list.$O\ - galign.$O\ - gobj.$O\ - ggen.$O\ - gsubr.$O\ cgen.$O\ cgen64.$O\ cplx.$O\ + galign.$O\ + ggen.$O\ + gobj.$O\ + gsubr.$O\ + list.$O\ peep.$O\ + pgen.$O\ reg.$O\ LIB=\ diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c index 223152536..25adb38c0 100644 --- a/src/cmd/8g/ggen.c +++ b/src/cmd/8g/ggen.c @@ -7,106 +7,9 @@ #include "gg.h" #include "opt.h" -static Prog *pret; - void -compile(Node *fn) +defframe(Prog *ptxt) { - Plist *pl; - Node nod1; - Prog *ptxt; - int32 lno; - Type *t; - Iter save; - - if(newproc == N) { - newproc = sysfunc("newproc"); - deferproc = sysfunc("deferproc"); - deferreturn = sysfunc("deferreturn"); - panicindex = sysfunc("panicindex"); - panicslice = sysfunc("panicslice"); - throwreturn = sysfunc("throwreturn"); - } - - if(fn->nbody == nil) - return; - - // set up domain for labels - clearlabels(); - - lno = setlineno(fn); - - curfn = fn; - dowidth(curfn->type); - - if(curfn->type->outnamed) { - // add clearing of the output parameters - t = structfirst(&save, getoutarg(curfn->type)); - while(t != T) { - if(t->nname != N) - curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody); - t = structnext(&save); - } - } - - hasdefer = 0; - walk(curfn); - if(nerrors != 0 || isblank(curfn->nname)) - goto ret; - - allocparams(); - - continpc = P; - breakpc = P; - - pl = newplist(); - pl->name = curfn->nname; - - setlineno(curfn); - - nodconst(&nod1, types[TINT32], 0); - ptxt = gins(ATEXT, curfn->nname, &nod1); - afunclit(&ptxt->from); - - ginit(); - genlist(curfn->enter); - - pret = nil; - if(hasdefer || curfn->exit) { - Prog *p1; - - p1 = gjmp(nil); - pret = gjmp(nil); - patch(p1, pc); - } - - genlist(curfn->nbody); - gclean(); - checklabels(); - if(nerrors != 0) - goto ret; - if(curfn->endlineno) - lineno = curfn->endlineno; - - if(curfn->type->outtuple != 0) - ginscall(throwreturn, 0); - - if(pret) - patch(pret, pc); - ginit(); - if(hasdefer) - ginscall(deferreturn, 0); - if(curfn->exit) - genlist(curfn->exit); - gclean(); - if(nerrors != 0) - goto ret; - pc->as = ARET; // overwrite AEND - pc->lineno = lineno; - - if(!debug['N'] || debug['R'] || debug['P']) { - regopt(ptxt); - } // fill in argument size ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr); @@ -115,12 +18,6 @@ compile(Node *fn) maxstksize = stksize; ptxt->to.offset = rnd(maxstksize+maxarg, widthptr); maxstksize = 0; - - if(debug['f']) - frame(0); - -ret: - lineno = lno; } void @@ -200,7 +97,7 @@ ginscall(Node *f, int proc) if(proc == 2) { nodreg(®, types[TINT64], D_AX); gins(ATESTL, ®, ®); - patch(gbranch(AJNE, T), pret); + patch(gbranch(AJNE, T), retpc); } break; } @@ -391,8 +288,8 @@ void cgen_ret(Node *n) { genlist(n->list); // copy out args - if(pret) - gjmp(pret); + if(retpc) + gjmp(retpc); else gins(ARET, N, N); } diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 7de7753a2..c426a88a4 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -781,6 +781,7 @@ asmb(void) cflush(); } break; + case Hdarwin: case Hwindows: seek(cout, symo, 0); if(debug['v']) diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index f84a30f39..440dcb77f 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -218,7 +218,7 @@ main(int argc, char *argv[]) */ tlsoffset = 0x468; machoinit(); - HEADR = MACHORESERVE; + HEADR = INITIAL_MACHO_HEADR; if(INITTEXT == -1) INITTEXT = 4096+HEADR; if(INITDAT == -1) diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index b3aa9aded..064725c1d 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -35,9 +35,17 @@ systems. For example: // #include <png.h> import "C" -C identifiers or field names that are keywords in Go can be -accessed by prefixing them with an underscore: if x points at -a C struct with a field named "type", x._type accesses the field. +Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config +tool using a '#cgo pkg-config:' directive followed by the package names. +For example: + + // #cgo pkg-config: png cairo + // #include <png.h> + import "C" + +Within the Go file, C identifiers or field names that are keywords in Go +can be accessed by prefixing them with an underscore: if x points at a C +struct with a field named "type", x._type accesses the field. The standard C numeric types are available under the names C.char, C.schar (signed char), C.uchar (unsigned char), diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index ac6561345..fa7602cf2 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -100,27 +100,81 @@ NextLine: fatalf("%s: bad #cgo option: %s", srcfile, fields[0]) } - if k != "CFLAGS" && k != "LDFLAGS" { - fatalf("%s: unsupported #cgo option %s", srcfile, k) - } - - v := strings.TrimSpace(fields[1]) - args, err := splitQuoted(v) + args, err := splitQuoted(fields[1]) if err != nil { - fatalf("%s: bad #cgo option %s: %s", srcfile, k, err.String()) + fatalf("%s: bad #cgo option %s: %s", srcfile, k, err) } - if oldv, ok := p.CgoFlags[k]; ok { - p.CgoFlags[k] = oldv + " " + v - } else { - p.CgoFlags[k] = v + for _, arg := range args { + if !safeName(arg) { + fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg) + } } - if k == "CFLAGS" { - p.GccOptions = append(p.GccOptions, args...) + + switch k { + + case "CFLAGS", "LDFLAGS": + p.addToFlag(k, args) + + case "pkg-config": + cflags, ldflags, err := pkgConfig(args) + if err != nil { + fatalf("%s: bad #cgo option %s: %s", srcfile, k, err) + } + p.addToFlag("CFLAGS", cflags) + p.addToFlag("LDFLAGS", ldflags) + + default: + fatalf("%s: unsupported #cgo option %s", srcfile, k) + } } f.Preamble = strings.Join(linesOut, "\n") } +// addToFlag appends args to flag. All flags are later written out onto the +// _cgo_flags file for the build system to use. +func (p *Package) addToFlag(flag string, args []string) { + if oldv, ok := p.CgoFlags[flag]; ok { + p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ") + } else { + p.CgoFlags[flag] = strings.Join(args, " ") + } + if flag == "CFLAGS" { + // We'll also need these when preprocessing for dwarf information. + p.GccOptions = append(p.GccOptions, args...) + } +} + +// pkgConfig runs pkg-config and extracts --libs and --cflags information +// for packages. +func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) { + for _, name := range packages { + if len(name) == 0 || name[0] == '-' { + return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name)) + } + } + + args := append([]string{"pkg-config", "--cflags"}, packages...) + stdout, stderr, ok := run(nil, args) + if !ok { + os.Stderr.Write(stderr) + return nil, nil, os.NewError("pkg-config failed") + } + cflags, err = splitQuoted(string(stdout)) + if err != nil { + return + } + + args = append([]string{"pkg-config", "--libs"}, packages...) + stdout, stderr, ok = run(nil, args) + if !ok { + os.Stderr.Write(stderr) + return nil, nil, os.NewError("pkg-config failed") + } + ldflags, err = splitQuoted(string(stdout)) + return +} + // splitQuoted splits the string s around each instance of one or more consecutive // white space characters while taking into account quotes and escaping, and // returns an array of substrings of s or an empty list if s contains only white space. @@ -182,6 +236,20 @@ func splitQuoted(s string) (r []string, err os.Error) { return args, err } +var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz") + +func safeName(s string) bool { + if s == "" { + return false + } + for i := 0; i < len(s); i++ { + if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { + return false + } + } + return true +} + // Translate rewrites f.AST, the original Go input, to remove // references to the imported package C, replacing them with // references to the equivalent Go types, functions, and variables. diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 2ce4e9752..dbc7bcf69 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -142,7 +142,7 @@ func dynimport(obj string) { if f, err := pe.Open(obj); err == nil { sym, err := f.ImportedSymbols() if err != nil { - fatalf("cannot load imported symbols from PE file %s: v", obj, err) + fatalf("cannot load imported symbols from PE file %s: %v", obj, err) } for _, s := range sym { ss := strings.Split(s, ":", -1) diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile index dbfd86474..286618ec1 100644 --- a/src/cmd/gc/Makefile +++ b/src/cmd/gc/Makefile @@ -49,7 +49,7 @@ include ../../Make.clib install: $(LIB) y1.tab.c: y.tab.c # make yystate global, yytname mutable - cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c + cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too awk -f bisonerrors y.output go.errors >yerr.h diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c index a8454bf13..7fcac4833 100644 --- a/src/cmd/gc/align.c +++ b/src/cmd/gc/align.c @@ -234,9 +234,11 @@ dowidth(Type *t) if(t->bound > cap) yyerror("type %lT larger than address space", t); w = t->bound * t->type->width; - if(w == 0) - w = 1; t->align = t->type->align; + if(w == 0) { + w = 1; + t->align = 1; + } } else if(t->bound == -1) { w = sizeof_Array; @@ -253,10 +255,10 @@ dowidth(Type *t) if(t->funarg) fatal("dowidth fn struct %T", t); w = widstruct(t, 0, 1); - if(w == 0) + if(w == 0) { w = 1; - //if(t->align < widthptr) - // warn("align %d: %T\n", t->align, t); + t->align = 1; + } break; case TFUNC: diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c index eb7014366..906dadbc9 100644 --- a/src/cmd/gc/closure.c +++ b/src/cmd/gc/closure.c @@ -75,7 +75,7 @@ closurebody(NodeList *body) } void -typecheckclosure(Node *func) +typecheckclosure(Node *func, int top) { Node *oldfn; NodeList *l; @@ -106,6 +106,10 @@ typecheckclosure(Node *func) v->op = 0; continue; } + // For a closure that is called in place, but not + // inside a go statement, avoid moving variables to the heap. + if ((top & (Ecall|Eproc)) == Ecall) + v->heapaddr->etype = 1; typecheck(&v->heapaddr, Erv); func->enter = list(func->enter, v->heapaddr); v->heapaddr = N; @@ -199,3 +203,41 @@ walkclosure(Node *func, NodeList **init) walkexpr(&call, init); return call; } + +// Special case for closures that get called in place. +// Optimize runtime.closure(X, __func__xxxx_, .... ) away +// to __func__xxxx_(Y ....). +// On entry, expect n->op == OCALL, n->left->op == OCLOSURE. +void +walkcallclosure(Node *n, NodeList **init) +{ + Node *z; + NodeList *ll, *cargs; + + walkexpr(&n->left, init); + cargs = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->next; // skip second + + n->left = n->left // FUNC runtime.closure + ->list // arguments + ->next // skip first + ->n // AS (to indreg) + ->right; // argument == the generated function + + // New arg list for n. First the closure-args, stolen from + // runtime.closure's 3rd and following, + ll = nil; + for (; cargs; cargs = cargs->next) + ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg) + + // then an extra zero, to fill the dummy return pointer slot, + z = nod(OXXX, N, N); + nodconst(z, types[TUINTPTR], 0); + z->typecheck = 1; + ll = list(ll, z); + + // and finally the original parameter list. + n->list = concat(ll, n->list); +} diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c index a36ec68c0..8fe9072b2 100644 --- a/src/cmd/gc/const.c +++ b/src/cmd/gc/const.c @@ -103,6 +103,8 @@ convlit1(Node **np, Type *t, int explicit) case ORSH: convlit1(&n->left, t, explicit && isideal(n->left->type)); t = n->left->type; + if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT) + n->val = toint(n->val); if(t != T && !isint[t->etype]) { yyerror("invalid operation: %#N (shift of type %T)", n, t); t = T; @@ -514,6 +516,8 @@ evconst(Node *n) n->right = nr; if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype])) goto illegal; + nl->val = toint(nl->val); + nr->val = toint(nr->val); break; } diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c index 99af18d9f..78c676346 100644 --- a/src/cmd/gc/dcl.c +++ b/src/cmd/gc/dcl.c @@ -188,6 +188,7 @@ declare(Node *n, int ctxt) else if(n->op == ONAME) gen = ++vargen; pushdcl(s); + n->curfn = curfn; } if(ctxt == PAUTO) n->xoffset = BADWIDTH; @@ -524,6 +525,30 @@ colas(NodeList *left, NodeList *right) } /* + * declare the arguments in an + * interface field declaration. + */ +void +ifacedcl(Node *n) +{ + if(n->op != ODCLFIELD || n->right == N) + fatal("ifacedcl"); + + dclcontext = PAUTO; + markdcl(); + funcdepth++; + n->outer = curfn; + curfn = n; + funcargs(n->right); + + // funcbody is normally called after the parser has + // seen the body of a function but since an interface + // field declaration does not have a body, we must + // call it now to pop the current declaration context. + funcbody(n); +} + +/* * declare the function proper * and declare the arguments. * called in extern-declaration context @@ -1226,9 +1251,6 @@ funccompile(Node *n, int isclosure) if(curfn) fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym); - curfn = n; - typechecklist(n->nbody, Etop); - curfn = nil; stksize = 0; dclcontext = PAUTO; diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c index 8ad6c437d..0b6f5bbd8 100644 --- a/src/cmd/gc/gen.c +++ b/src/cmd/gc/gen.c @@ -59,6 +59,8 @@ allocparams(void) fatal("bad width"); stksize += w; stksize = rnd(stksize, n->type->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; } lineno = lno; @@ -698,6 +700,8 @@ tempname(Node *n, Type *t) w = t->width; stksize += w; stksize = rnd(stksize, t->align); + if(thechar == '5') + stksize = rnd(stksize, widthptr); n->xoffset = -stksize; n->pun = anyregalloc(); } diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h index 359881e11..f5c0443f8 100644 --- a/src/cmd/gc/go.h +++ b/src/cmd/gc/go.h @@ -254,6 +254,7 @@ struct Node Node* ntype; Node* defn; Node* pack; // real package for import . names + Node* curfn; // function for local variables // ONAME func param with PHEAP Node* heapaddr; // temp holding heap address of param @@ -517,15 +518,16 @@ enum enum { - Etop = 1<<1, // evaluated at statement level - Erv = 1<<2, // evaluated in value context + Etop = 1<<1, // evaluated at statement level + Erv = 1<<2, // evaluated in value context Etype = 1<<3, - Ecall = 1<<4, // call-only expressions are ok + Ecall = 1<<4, // call-only expressions are ok Efnstruct = 1<<5, // multivalue function returns are ok Eiota = 1<<6, // iota is ok Easgn = 1<<7, // assigning to expression Eindir = 1<<8, // indirecting through expression Eaddr = 1<<9, // taking address of expression + Eproc = 1<<10, // inside a go statement }; #define BITS 5 @@ -815,8 +817,9 @@ int bset(Bits a, uint n); */ Node* closurebody(NodeList *body); void closurehdr(Node *ntype); -void typecheckclosure(Node *func); +void typecheckclosure(Node *func, int top); Node* walkclosure(Node *func, NodeList **init); +void walkcallclosure(Node *n, NodeList **init); /* * const.c @@ -870,6 +873,7 @@ void funcbody(Node *n); void funccompile(Node *n, int isclosure); void funchdr(Node *n); Type* functype(Node *this, NodeList *in, NodeList *out); +void ifacedcl(Node *n); int isifacemethod(Type *f); void markdcl(void); Node* methodname(Node *n, Type *t); @@ -1209,6 +1213,7 @@ EXTERN Prog* continpc; EXTERN Prog* breakpc; EXTERN Prog* pc; EXTERN Prog* firstpc; +EXTERN Prog* retpc; EXTERN Node* nodfp; @@ -1222,6 +1227,7 @@ void cgen_callinter(Node *n, Node *res, int proc); void cgen_ret(Node *n); void clearfat(Node *n); void compile(Node*); +void defframe(Prog*); int dgostringptr(Sym*, int off, char *str); int dgostrlitptr(Sym*, int off, Strlit*); int dstringptr(Sym *s, int off, char *str); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y index 7adfd002a..fdaab4fa4 100644 --- a/src/cmd/gc/go.y +++ b/src/cmd/gc/go.y @@ -1380,6 +1380,7 @@ interfacedcl: new_name indcl { $$ = nod(ODCLFIELD, $1, $2); + ifacedcl($$); } | packname { diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c index af4eb0336..8818db08c 100644 --- a/src/cmd/gc/init.c +++ b/src/cmd/gc/init.c @@ -182,11 +182,14 @@ fninit(NodeList *n) // (11) a = nod(ORETURN, N, N); r = list(r, a); - exportsym(fn->nname); fn->nbody = r; funcbody(fn); + + curfn = fn; typecheck(&fn, Etop); + typechecklist(r, Etop); + curfn = nil; funccompile(fn, 0); } diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c index 04dd0d5b9..5e2f73fc5 100644 --- a/src/cmd/gc/lex.c +++ b/src/cmd/gc/lex.c @@ -235,13 +235,14 @@ main(int argc, char *argv[]) if(debug['f']) frame(1); - // Process top-level declarations in three phases. + // Process top-level declarations in four phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. - // Phase 3: Function bodies. + // Phase 3: Type check function bodies. + // Phase 4: Compile function bodies. defercheckwidth(); for(l=xtop; l; l=l->next) if(l->n->op != ODCL && l->n->op != OAS) @@ -251,17 +252,28 @@ main(int argc, char *argv[]) typecheck(&l->n, Etop); resumetypecopy(); resumecheckwidth(); + + for(l=xtop; l; l=l->next) + if(l->n->op == ODCLFUNC) { + curfn = l->n; + typechecklist(l->n->nbody, Etop); + } + curfn = nil; + for(l=xtop; l; l=l->next) if(l->n->op == ODCLFUNC) funccompile(l->n, 0); + if(nerrors == 0) fninit(xtop); + while(closures) { l = closures; closures = nil; for(; l; l=l->next) funccompile(l->n, 1); } + dclchecks(); if(nerrors) diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c index 9f4b7b318..f34fc76c8 100644 --- a/src/cmd/gc/obj.c +++ b/src/cmd/gc/obj.c @@ -284,6 +284,7 @@ stringsym(char *s, int len) off = dsname(sym, off, s+n, m); } off = duint8(sym, off, 0); // terminating NUL for runtime + off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment ggloblsym(sym, off, 1); text(); diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c new file mode 100644 index 000000000..9bd845dde --- /dev/null +++ b/src/cmd/gc/pgen.c @@ -0,0 +1,119 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#undef EXTERN +#define EXTERN +#include "gg.h" +#include "opt.h" + +void +compile(Node *fn) +{ + Plist *pl; + Node nod1, *n; + Prog *ptxt; + int32 lno; + Type *t; + Iter save; + + if(newproc == N) { + newproc = sysfunc("newproc"); + deferproc = sysfunc("deferproc"); + deferreturn = sysfunc("deferreturn"); + panicindex = sysfunc("panicindex"); + panicslice = sysfunc("panicslice"); + throwreturn = sysfunc("throwreturn"); + } + + if(fn->nbody == nil) + return; + + // set up domain for labels + clearlabels(); + + lno = setlineno(fn); + + curfn = fn; + dowidth(curfn->type); + + if(curfn->type->outnamed) { + // add clearing of the output parameters + t = structfirst(&save, getoutarg(curfn->type)); + while(t != T) { + if(t->nname != N) { + n = nod(OAS, t->nname, N); + typecheck(&n, Etop); + curfn->nbody = concat(list1(n), curfn->nbody); + } + t = structnext(&save); + } + } + + hasdefer = 0; + walk(curfn); + if(nerrors != 0 || isblank(curfn->nname)) + goto ret; + + allocparams(); + + continpc = P; + breakpc = P; + + pl = newplist(); + pl->name = curfn->nname; + + setlineno(curfn); + + nodconst(&nod1, types[TINT32], 0); + ptxt = gins(ATEXT, curfn->nname, &nod1); + afunclit(&ptxt->from); + + ginit(); + genlist(curfn->enter); + + retpc = nil; + if(hasdefer || curfn->exit) { + Prog *p1; + + p1 = gjmp(nil); + retpc = gjmp(nil); + patch(p1, pc); + } + + genlist(curfn->nbody); + gclean(); + checklabels(); + if(nerrors != 0) + goto ret; + if(curfn->endlineno) + lineno = curfn->endlineno; + + if(curfn->type->outtuple != 0) + ginscall(throwreturn, 0); + + if(retpc) + patch(retpc, pc); + ginit(); + if(hasdefer) + ginscall(deferreturn, 0); + if(curfn->exit) + genlist(curfn->exit); + gclean(); + if(nerrors != 0) + goto ret; + pc->as = ARET; // overwrite AEND + pc->lineno = lineno; + + if(!debug['N'] || debug['R'] || debug['P']) { + regopt(ptxt); + } + + defframe(ptxt); + + if(debug['f']) + frame(0); + +ret: + lineno = lno; +} diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c index be96a1477..eb7ef31ec 100644 --- a/src/cmd/gc/sinit.c +++ b/src/cmd/gc/sinit.c @@ -173,10 +173,10 @@ initfix(NodeList *l) /* * from here down is the walk analysis - * of composit literals. + * of composite literals. * most of the work is to generate * data statements for the constant - * part of the composit literal. + * part of the composite literal. */ static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init); diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index 326a5ba74..4c0819cd8 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3170,7 +3170,10 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) dumplist("genwrapper body", fn->nbody); funcbody(fn); + curfn = fn; typecheck(&fn, Etop); + typechecklist(fn->nbody, Etop); + curfn = nil; funccompile(fn, 0); } diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c index 9aaf3e6ef..44d08352d 100644 --- a/src/cmd/gc/typecheck.c +++ b/src/cmd/gc/typecheck.c @@ -29,8 +29,8 @@ static void typecheckfunc(Node*); static void checklvalue(Node*, char*); static void checkassign(Node*); static void checkassignlist(NodeList*); -static void stringtoarraylit(Node**); -static Node* resolve(Node*); +static void stringtoarraylit(Node**); +static Node* resolve(Node*); static Type* getforwtype(Node*); /* @@ -780,7 +780,7 @@ reswitch: n = r; goto reswitch; } - typecheck(&n->left, Erv | Etype | Ecall); + typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); l = n->left; if(l->op == ONAME && l->etype != 0) { if(n->isddd && l->etype != OAPPEND) @@ -794,7 +794,7 @@ reswitch: defaultlit(&n->left, T); l = n->left; if(l->op == OTYPE) { - if(n->isddd) + if(n->isddd || l->type->bound == -100) yyerror("invalid use of ... in type conversion", l); // pick off before type-checking arguments ok |= Erv; @@ -822,7 +822,13 @@ reswitch: case ODOTMETH: n->op = OCALLMETH; - typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver"); + // typecheckaste was used here but there wasn't enough + // information further down the call chain to know if we + // were testing a method receiver for unexported fields. + // It isn't necessary, so just do a sanity check. + tp = getthisx(t)->type->type; + if(l->left == N || !eqtype(l->left->type, tp)) + fatal("method receiver"); break; default: @@ -1021,9 +1027,9 @@ reswitch: // copy([]byte, string) if(isslice(n->left->type) && n->right->type->etype == TSTRING) { - if (n->left->type->type ==types[TUINT8]) - goto ret; - yyerror("arguments to copy have different element types: %lT and string", n->left->type); + if (n->left->type->type == types[TUINT8]) + goto ret; + yyerror("arguments to copy have different element types: %lT and string", n->left->type); goto error; } @@ -1211,7 +1217,7 @@ reswitch: case OCLOSURE: ok |= Erv; - typecheckclosure(n); + typecheckclosure(n, top); if(n->type == T) goto error; goto ret; @@ -1240,11 +1246,15 @@ reswitch: goto ret; case ODEFER: - case OPROC: ok |= Etop; typecheck(&n->left, Etop); goto ret; + case OPROC: + ok |= Etop; + typecheck(&n->left, Etop|Eproc); + goto ret; + case OFOR: ok |= Etop; typechecklist(n->ninit, Etop); @@ -2159,7 +2169,9 @@ addrescapes(Node *n) if(n->noescape) break; switch(n->class) { - case PAUTO: + case PPARAMREF: + addrescapes(n->defn); + break; case PPARAM: case PPARAMOUT: // if func param, need separate temporary @@ -2167,16 +2179,17 @@ addrescapes(Node *n) // the function type has already been checked // (we're in the function body) // so the param already has a valid xoffset. - if(n->class == PPARAM || n->class == PPARAMOUT) { - // expression to refer to stack copy - n->stackparam = nod(OPARAM, n, N); - n->stackparam->type = n->type; - n->stackparam->addable = 1; - if(n->xoffset == BADWIDTH) - fatal("addrescapes before param assignment"); - n->stackparam->xoffset = n->xoffset; - n->xoffset = 0; - } + + // expression to refer to stack copy + n->stackparam = nod(OPARAM, n, N); + n->stackparam->type = n->type; + n->stackparam->addable = 1; + if(n->xoffset == BADWIDTH) + fatal("addrescapes before param assignment"); + n->stackparam->xoffset = n->xoffset; + n->xoffset = 0; + // fallthrough + case PAUTO: n->class |= PHEAP; n->addable = 0; @@ -2189,7 +2202,9 @@ addrescapes(Node *n) snprint(buf, sizeof buf, "&%S", n->sym); n->heapaddr->sym = lookup(buf); n->heapaddr->class = PHEAP-1; // defer tempname to allocparams - curfn->dcl = list(curfn->dcl, n->heapaddr); + n->heapaddr->ullman = 1; + n->curfn->dcl = list(n->curfn->dcl, n->heapaddr); + break; } break; diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index b3b400556..ccc65ff21 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -66,6 +66,7 @@ walk(Node *fn) int lno; curfn = fn; + if(debug['W']) { snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); dumplist(s, curfn->nbody); @@ -73,7 +74,7 @@ walk(Node *fn) if(curfn->type->outtuple) if(walkret(curfn->nbody)) yyerror("function ends without a return statement"); - typechecklist(curfn->nbody, Etop); + lno = lineno; for(l=fn->dcl; l; l=l->next) { n = l->n; @@ -468,8 +469,10 @@ walkstmt(Node **np) case OPANIC: case OEMPTY: case ORECOVER: - if(n->typecheck == 0) + if(n->typecheck == 0) { + dump("missing typecheck:", n); fatal("missing typecheck"); + } init = n->ninit; n->ninit = nil; walkexpr(&n, &init); @@ -770,8 +773,15 @@ walkexpr(Node **np, NodeList **init) t = n->left->type; if(n->list && n->list->n->op == OAS) goto ret; - walkexpr(&n->left, init); + + if(n->left->op == OCLOSURE) { + walkcallclosure(n, init); + t = n->left->type; + } else + walkexpr(&n->left, init); + walkexprlist(n->list, init); + ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init); n->list = reorder1(ll); if(isselect(n)) { @@ -1525,7 +1535,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) static int fncall(Node *l, Type *rt) { - if(l->ullman >= UINF) + if(l->ullman >= UINF || l->op == OINDEXMAP) return 1; if(eqtype(l->type, rt)) return 0; diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go index f8b95e387..d863ca0d8 100644 --- a/src/cmd/godoc/spec.go +++ b/src/cmd/godoc/spec.go @@ -99,7 +99,8 @@ func (p *ebnfParser) parseTerm() bool { case token.STRING: p.next() - if p.tok == token.ELLIPSIS { + const ellipsis = "…" // U+2026, the horizontal ellipsis character + if p.tok == token.ILLEGAL && p.lit == ellipsis { p.next() p.expect(token.STRING) } @@ -157,7 +158,7 @@ func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) { p.out = out p.src = src p.file = fset.AddFile("", fset.Base(), len(src)) - p.scanner.Init(p.file, src, p, 0) + p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars) p.next() // initializes pos, tok, lit // process source diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go index 4f7e923e3..ba2061a00 100644 --- a/src/cmd/gofix/main.go +++ b/src/cmd/gofix/main.go @@ -248,17 +248,5 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) { f1.Write(b1) f2.Write(b2) - diffcmd, err := exec.LookPath("diff") - if err != nil { - return nil, err - } - - c, err := exec.Run(diffcmd, []string{"diff", f1.Name(), f2.Name()}, nil, "", - exec.DevNull, exec.Pipe, exec.MergeWithStdout) - if err != nil { - return nil, err - } - defer c.Close() - - return ioutil.ReadAll(c.Stdout) + return exec.Command("diff", f1.Name(), f2.Name()).CombinedOutput() } diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 5dd801d90..16bcd3c4d 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -245,14 +245,14 @@ func gofmtMain() { func diff(b1, b2 []byte) (data []byte, err os.Error) { f1, err := ioutil.TempFile("", "gofmt") if err != nil { - return nil, err + return } defer os.Remove(f1.Name()) defer f1.Close() f2, err := ioutil.TempFile("", "gofmt") if err != nil { - return nil, err + return } defer os.Remove(f2.Name()) defer f2.Close() @@ -260,17 +260,5 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) { f1.Write(b1) f2.Write(b2) - diffcmd, err := exec.LookPath("diff") - if err != nil { - return nil, err - } - - c, err := exec.Run(diffcmd, []string{"diff", "-u", f1.Name(), f2.Name()}, - nil, "", exec.DevNull, exec.Pipe, exec.MergeWithStdout) - if err != nil { - return nil, err - } - defer c.Close() - - return ioutil.ReadAll(c.Stdout) + return exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput() } diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go index 15845b574..13c37d0a2 100644 --- a/src/cmd/goinstall/doc.go +++ b/src/cmd/goinstall/doc.go @@ -3,7 +3,6 @@ // license that can be found in the LICENSE file. /* - Goinstall is an experiment in automatic package installation. It installs packages, possibly downloading them from the internet. It maintains a list of public Go packages at http://godashboard.appspot.com/package. @@ -100,5 +99,59 @@ Instead, it invokes "make install" after locating the package sources. For local packages without a Makefile and all remote packages, goinstall creates and uses a temporary Makefile constructed from the import path and the list of Go files in the package. + + +The GOPATH Environment Variable + +GOPATH may be set to a colon-separated list of paths inside which Go code, +package objects, and executables may be found. + +Set a GOPATH to use goinstall to build and install your own code and +external libraries outside of the Go tree (and to avoid writing Makefiles). + +The top-level directory structure of a GOPATH is prescribed: + +The 'src' directory is for source code. The directory naming inside 'src' +determines the package import path or executable name. + +The 'pkg' directory is for package objects. Like the Go tree, package objects +are stored inside a directory named after the target operating system and +processor architecture ('pkg/$GOOS_$GOARCH'). +A package whose source is located at '$GOPATH/src/foo/bar' would be imported +as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'. + +The 'bin' directory is for executable files. +Goinstall installs program binaries using the name of the source folder. +A binary whose source is at 'src/foo/qux' would be built and installed to +'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that +you can put the bin directory in your PATH.) + +Here's an example directory layout: + + GOPATH=/home/user/gocode + + /home/user/gocode/ + src/foo/ + bar/ (go code in package bar) + qux/ (go code in package main) + bin/qux (executable file) + pkg/linux_amd64/foo/bar.a (object file) + +Run 'goinstall foo/bar' to build and install the package 'foo/bar' +(and its dependencies). +Goinstall will search each GOPATH (in order) for 'src/foo/bar'. +If the directory cannot be found, goinstall will attempt to fetch the +source from a remote repository and write it to the 'src' directory of the +first GOPATH (or $GOROOT/src/pkg if GOPATH is not set). + +Goinstall recognizes relative and absolute paths (paths beginning with / or .). +The following commands would build our example packages: + + goinstall /home/user/gocode/src/foo/bar # build and install foo/bar + cd /home/user/gocode/src/foo + goinstall ./bar # build and install foo/bar (again) + cd qux + goinstall . # build and install foo/qux + */ package documentation diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go index 7dad596ab..2edf85efd 100644 --- a/src/cmd/goinstall/download.go +++ b/src/cmd/goinstall/download.go @@ -31,23 +31,36 @@ func maybeReportToDashboard(path string) { } } -var googlecode = regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`) -var github = regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`) -var bitbucket = regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`) -var launchpad = regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`) +var vcsPatterns = map[string]*regexp.Regexp{ + "googlecode": regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`), + "github": regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), + "bitbucket": regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), + "launchpad": regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), +} + +// isRemote returns true if the provided package path +// matches one of the supported remote repositories. +func isRemote(pkg string) bool { + for _, r := range vcsPatterns { + if r.MatchString(pkg) { + return true + } + } + return false +} // download checks out or updates pkg from the remote server. func download(pkg, srcDir string) os.Error { if strings.Contains(pkg, "..") { return os.ErrorString("invalid path (contains ..)") } - if m := bitbucket.FindStringSubmatch(pkg); m != nil { + if m := vcsPatterns["bitbucket"].FindStringSubmatch(pkg); m != nil { if err := vcsCheckout(&hg, srcDir, m[1], "http://"+m[1], m[1]); err != nil { return err } return nil } - if m := googlecode.FindStringSubmatch(pkg); m != nil { + if m := vcsPatterns["googlecode"].FindStringSubmatch(pkg); m != nil { var v *vcs switch m[2] { case "hg": @@ -63,7 +76,7 @@ func download(pkg, srcDir string) os.Error { } return nil } - if m := github.FindStringSubmatch(pkg); m != nil { + if m := vcsPatterns["github"].FindStringSubmatch(pkg); m != nil { if strings.HasSuffix(m[1], ".git") { return os.ErrorString("repository " + pkg + " should not have .git suffix") } @@ -72,7 +85,7 @@ func download(pkg, srcDir string) os.Error { } return nil } - if m := launchpad.FindStringSubmatch(pkg); m != nil { + if m := vcsPatterns["launchpad"].FindStringSubmatch(pkg); m != nil { // Either lp.net/<project>[/<series>[/<path>]] // or lp.net/~<user or team>/<project>/<branch>[/<path>] if err := vcsCheckout(&bzr, srcDir, m[1], "https://"+m[1], m[1]); err != nil { diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go index 6cd92907a..721e719d2 100644 --- a/src/cmd/goinstall/main.go +++ b/src/cmd/goinstall/main.go @@ -12,7 +12,6 @@ import ( "flag" "fmt" "go/token" - "io" "io/ioutil" "os" "path/filepath" @@ -32,9 +31,8 @@ var ( argv0 = os.Args[0] errors = false parents = make(map[string]string) - root = runtime.GOROOT() visit = make(map[string]status) - logfile = filepath.Join(root, "goinstall.log") + logfile = filepath.Join(runtime.GOROOT(), "goinstall.log") installedPkgs = make(map[string]bool) allpkg = flag.Bool("a", false, "install all previously installed packages") @@ -52,14 +50,30 @@ const ( done ) +func logf(format string, args ...interface{}) { + format = "%s: " + format + args = append([]interface{}{argv0}, args...) + fmt.Fprintf(os.Stderr, format, args...) +} + +func vlogf(format string, args ...interface{}) { + if *verbose { + logf(format, args...) + } +} + +func errorf(format string, args ...interface{}) { + errors = true + logf(format, args...) +} + func main() { flag.Usage = usage flag.Parse() - if root == "" { + if runtime.GOROOT() == "" { fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0) os.Exit(1) } - root += filepath.FromSlash("/src/pkg/") // special case - "unsafe" is already installed visit["unsafe"] = done @@ -88,6 +102,11 @@ func main() { usage() } for _, path := range args { + if strings.HasPrefix(path, "http://") { + errorf("'http://' used in remote path, try '%s'\n", path[7:]) + continue + } + install(path, "") } if errors { @@ -143,49 +162,44 @@ func install(pkg, parent string) { } visit[pkg] = visiting parents[pkg] = parent - if *verbose { - fmt.Println(pkg) - } + + vlogf("%s: visit\n", pkg) // Check whether package is local or remote. // If remote, download or update it. - var dir string - proot := gopath[0] // default to GOROOT - local := false - if strings.HasPrefix(pkg, "http://") { - fmt.Fprintf(os.Stderr, "%s: %s: 'http://' used in remote path, try '%s'\n", argv0, pkg, pkg[7:]) - errors = true + proot, pkg, err := findPackageRoot(pkg) + // Don't build the standard library. + if err == nil && proot.goroot && isStandardPath(pkg) { + if parent == "" { + errorf("%s: can not goinstall the standard library\n", pkg) + } else { + vlogf("%s: skipping standard library\n", pkg) + } + visit[pkg] = done return } - if isLocalPath(pkg) { - dir = pkg - local = true - } else if isStandardPath(pkg) { - dir = filepath.Join(root, filepath.FromSlash(pkg)) - local = true - } else { - proot = findPkgroot(pkg) - err := download(pkg, proot.srcDir()) - dir = filepath.Join(proot.srcDir(), pkg) - if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err) - errors = true - visit[pkg] = done - return - } + // Download remote packages if not found or forced with -u flag. + remote := isRemote(pkg) + if remote && (err == ErrPackageNotFound || (err == nil && *update)) { + vlogf("%s: download\n", pkg) + err = download(pkg, proot.srcDir()) } + if err != nil { + errorf("%s: %v\n", pkg, err) + visit[pkg] = done + return + } + dir := filepath.Join(proot.srcDir(), pkg) // Install prerequisites. dirInfo, err := scanDir(dir, parent == "") if err != nil { - fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err) - errors = true + errorf("%s: %v\n", pkg, err) visit[pkg] = done return } if len(dirInfo.goFiles) == 0 { - fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg) - errors = true + errorf("%s: package has no files\n", pkg) visit[pkg] = done return } @@ -198,22 +212,16 @@ func install(pkg, parent string) { // Install this package. if !errors { isCmd := dirInfo.pkgName == "main" - if err := domake(dir, pkg, proot, local, isCmd); err != nil { - fmt.Fprintf(os.Stderr, "%s: installing %s: %s\n", argv0, pkg, err) - errors = true - } else if !local && *logPkgs { - // mark this package as installed in $GOROOT/goinstall.log + if err := domake(dir, pkg, proot, isCmd); err != nil { + errorf("installing: %v\n", err) + } else if remote && *logPkgs { + // mark package as installed in $GOROOT/goinstall.log logPackage(pkg) } } visit[pkg] = done } -// Is this a local path? /foo ./foo ../foo . .. -func isLocalPath(s string) bool { - const sep = string(filepath.Separator) - return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".." -} // Is this a standard package path? strings container/vector etc. // Assume that if the first element has a dot, it's a domain name @@ -237,40 +245,22 @@ func quietRun(dir string, stdin []byte, cmd ...string) os.Error { } // genRun implements run and quietRun. -func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error { - bin, err := exec.LookPath(cmd[0]) +func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error { + cmd := exec.Command(arg[0], arg[1:]...) + cmd.Stdin = bytes.NewBuffer(stdin) + cmd.Dir = dir + vlogf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " ")) + out, err := cmd.CombinedOutput() if err != nil { - return err - } - p, err := exec.Run(bin, cmd, os.Environ(), dir, exec.Pipe, exec.Pipe, exec.MergeWithStdout) - if *verbose { - fmt.Fprintf(os.Stderr, "%s: %s; %s %s\n", argv0, dir, bin, strings.Join(cmd[1:], " ")) - } - if err != nil { - return err - } - go func() { - p.Stdin.Write(stdin) - p.Stdin.Close() - }() - var buf bytes.Buffer - io.Copy(&buf, p.Stdout) - io.Copy(&buf, p.Stdout) - w, err := p.Wait(0) - p.Close() - if err != nil { - return err - } - if !w.Exited() || w.ExitStatus() != 0 { if !quiet || *verbose { if dir != "" { dir = "cd " + dir + "; " } - fmt.Fprintf(os.Stderr, "%s: === %s%s\n", argv0, dir, strings.Join(cmd, " ")) - os.Stderr.Write(buf.Bytes()) - fmt.Fprintf(os.Stderr, "--- %s\n", w) + fmt.Fprintf(os.Stderr, "%s: === %s%s\n", cmd.Path, dir, strings.Join(cmd.Args, " ")) + os.Stderr.Write(out) + fmt.Fprintf(os.Stderr, "--- %s\n", err) } - return os.ErrorString("running " + cmd[0] + ": " + w.String()) + return os.ErrorString("running " + arg[0] + ": " + err.String()) } return nil } diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go index b2ca82b46..0c44481d7 100644 --- a/src/cmd/goinstall/make.go +++ b/src/cmd/goinstall/make.go @@ -14,26 +14,14 @@ import ( ) // domake builds the package in dir. -// If local is false, the package was copied from an external system. -// For non-local packages or packages without Makefiles, // domake generates a standard Makefile and passes it // to make on standard input. -func domake(dir, pkg string, root *pkgroot, local, isCmd bool) (err os.Error) { - needMakefile := true - if local { - _, err := os.Stat(dir + "/Makefile") - if err == nil { - needMakefile = false - } - } - cmd := []string{"gomake"} - var makefile []byte - if needMakefile { - if makefile, err = makeMakefile(dir, pkg, root, isCmd); err != nil { - return err - } - cmd = append(cmd, "-f-") +func domake(dir, pkg string, root *pkgroot, isCmd bool) (err os.Error) { + makefile, err := makeMakefile(dir, pkg, root, isCmd) + if err != nil { + return err } + cmd := []string{"bash", "gomake", "-f-"} if *clean { cmd = append(cmd, "clean") } @@ -51,16 +39,8 @@ func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error) targ := pkg targDir := root.pkgDir() if isCmd { - // use the last part of the package name only + // use the last part of the package name for targ _, targ = filepath.Split(pkg) - // if building the working dir use the directory name - if targ == "." { - d, err := filepath.Abs(dir) - if err != nil { - return nil, os.NewError("finding path: " + err.String()) - } - _, targ = filepath.Split(d) - } targDir = root.binDir() } dirInfo, err := scanDir(dir, isCmd) diff --git a/src/cmd/goinstall/path.go b/src/cmd/goinstall/path.go index 1153e0471..b8c392931 100644 --- a/src/cmd/goinstall/path.go +++ b/src/cmd/goinstall/path.go @@ -5,10 +5,12 @@ package main import ( + "fmt" "log" "os" "path/filepath" "runtime" + "strings" ) var ( @@ -19,6 +21,7 @@ var ( // set up gopath: parse and validate GOROOT and GOPATH variables func init() { + root := runtime.GOROOT() p, err := newPkgroot(root) if err != nil { log.Fatalf("Invalid GOROOT %q: %v", root, err) @@ -105,13 +108,42 @@ func (r *pkgroot) hasPkg(name string) bool { // TODO(adg): check object version is consistent } -// findPkgroot searches each of the gopath roots -// for the source code for the given import path. -func findPkgroot(importPath string) *pkgroot { + +var ErrPackageNotFound = os.NewError("package could not be found locally") + +// findPackageRoot takes an import or filesystem path and returns the +// root where the package source should be and the package import path. +func findPackageRoot(path string) (root *pkgroot, pkg string, err os.Error) { + if isLocalPath(path) { + if path, err = filepath.Abs(path); err != nil { + return + } + for _, r := range gopath { + rpath := r.srcDir() + string(filepath.Separator) + if !strings.HasPrefix(path, rpath) { + continue + } + root = r + pkg = path[len(rpath):] + return + } + err = fmt.Errorf("path %q not inside a GOPATH", path) + return + } + root = defaultRoot + pkg = path for _, r := range gopath { - if r.hasSrcDir(importPath) { - return r + if r.hasSrcDir(path) { + root = r + return } } - return defaultRoot + err = ErrPackageNotFound + return +} + +// Is this a local path? /foo ./foo ../foo . .. +func isLocalPath(s string) bool { + const sep = string(filepath.Separator) + return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".." } diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go index 8c81baf97..4cb3da23c 100644 --- a/src/cmd/gotest/gotest.go +++ b/src/cmd/gotest/gotest.go @@ -285,8 +285,8 @@ func doRun(argv []string, returnStdout bool) string { } cmd += `"` + v + `"` } - command = "sh" - argv = []string{"sh", "-c", cmd} + command = "bash" + argv = []string{"bash", "-c", cmd} } var err os.Error argv[0], err = exec.LookPath(argv[0]) diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go index 2dcb5234c..8ee3422e2 100644 --- a/src/cmd/hgpatch/main.go +++ b/src/cmd/hgpatch/main.go @@ -10,7 +10,6 @@ import ( "exec" "flag" "fmt" - "io" "io/ioutil" "os" "patch" @@ -333,6 +332,7 @@ func run(argv []string, input []byte) (out string, err os.Error) { err = os.EINVAL goto Error } + prog, ok := lookPathCache[argv[0]] if !ok { prog, err = exec.LookPath(argv[0]) @@ -341,40 +341,15 @@ func run(argv []string, input []byte) (out string, err os.Error) { } lookPathCache[argv[0]] = prog } - // fmt.Fprintf(os.Stderr, "%v\n", argv); - var cmd *exec.Cmd - if len(input) == 0 { - cmd, err = exec.Run(prog, argv, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout) - if err != nil { - goto Error - } - } else { - cmd, err = exec.Run(prog, argv, os.Environ(), "", exec.Pipe, exec.Pipe, exec.MergeWithStdout) - if err != nil { - goto Error - } - go func() { - cmd.Stdin.Write(input) - cmd.Stdin.Close() - }() - } - defer cmd.Close() - var buf bytes.Buffer - _, err = io.Copy(&buf, cmd.Stdout) - out = buf.String() - if err != nil { - cmd.Wait(0) - goto Error - } - w, err := cmd.Wait(0) - if err != nil { - goto Error + + cmd := exec.Command(prog, argv[1:]...) + if len(input) > 0 { + cmd.Stdin = bytes.NewBuffer(input) } - if !w.Exited() || w.ExitStatus() != 0 { - err = w - goto Error + bs, err := cmd.CombinedOutput() + if err == nil { + return string(bs), nil } - return Error: err = &runError{dup(argv), err} diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c index ed11f5e5a..de600f555 100644 --- a/src/cmd/ld/dwarf.c +++ b/src/cmd/ld/dwarf.c @@ -529,8 +529,10 @@ find_or_diag(DWDie *die, char* name) { DWDie *r; r = find(die, name); - if (r == nil) + if (r == nil) { diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name); + errorexit(); + } return r; } @@ -613,7 +615,7 @@ putattr(int form, int cls, vlong value, char *data) case DW_FORM_ref_addr: // reference to a DIE in the .info section if (data == nil) { - diag("null dwarf reference"); + diag("dwarf: null reference"); LPUT(0); // invalid dwarf, gdb will complain. } else { if (((DWDie*)data)->offs == 0) @@ -631,7 +633,7 @@ putattr(int form, int cls, vlong value, char *data) case DW_FORM_strp: // string case DW_FORM_indirect: // (see Section 7.5.3) default: - diag("Unsupported atribute form %d / class %d", form, cls); + diag("dwarf: unsupported attribute form %d / class %d", form, cls); errorexit(); } } @@ -823,7 +825,7 @@ decode_inuxi(uchar* p, int sz) inuxi = inuxi8; break; default: - diag("decode inuxi %d", sz); + diag("dwarf: decode inuxi %d", sz); errorexit(); } for (i = 0; i < sz; i++) @@ -1013,7 +1015,7 @@ defgotype(Sym *gotype) return find_or_diag(&dwtypes, "<unspecified>"); if (strncmp("type.", gotype->name, 5) != 0) { - diag("Type name doesn't start with \".type\": %s", gotype->name); + diag("dwarf: type name doesn't start with \".type\": %s", gotype->name); return find_or_diag(&dwtypes, "<unspecified>"); } name = gotype->name + 5; // could also decode from Type.string @@ -1164,7 +1166,7 @@ defgotype(Sym *gotype) break; default: - diag("definition of unknown kind %d: %s", kind, gotype->name); + diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name); die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name); newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>")); } @@ -1513,12 +1515,12 @@ decodez(char *s) ss = s + 1; // first is 0 while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) { if (o < 0 || o >= ftabsize) { - diag("corrupt z entry"); + diag("dwarf: corrupt z entry"); return 0; } f = ftab[o]; if (f == nil) { - diag("corrupt z entry"); + diag("dwarf: corrupt z entry"); return 0; } len += strlen(f) + 1; // for the '/' @@ -1630,11 +1632,11 @@ checknesting(void) int i; if (includetop < 0) { - diag("corrupt z stack"); + diag("dwarf: corrupt z stack"); errorexit(); } if (includetop >= nelem(includestack)) { - diag("nesting too deep"); + diag("dwarf: nesting too deep"); for (i = 0; i < nelem(includestack); i++) diag("\t%s", histfile[includestack[i].file]); errorexit(); @@ -1660,7 +1662,7 @@ inithist(Auto *a) // We have a new history. They are guaranteed to come completely // at the beginning of the compilation unit. if (a->aoffset != 1) { - diag("stray 'z' with offset %d", a->aoffset); + diag("dwarf: stray 'z' with offset %d", a->aoffset); return 0; } @@ -1915,7 +1917,7 @@ writelines(void) continue; if (unitstart < 0) { - diag("reachable code before seeing any history: %P", s->text); + diag("dwarf: reachable code before seeing any history: %P", s->text); continue; } @@ -1932,7 +1934,7 @@ writelines(void) for(q = s->text; q != P; q = q->link) { lh = searchhist(q->line); if (lh == nil) { - diag("corrupt history or bad absolute line: %P", q); + diag("dwarf: corrupt history or bad absolute line: %P", q); continue; } @@ -2066,7 +2068,7 @@ writeframes(void) // 4 is to exclude the length field. pad = CIERESERVE + frameo + 4 - cpos(); if (pad < 0) { - diag("CIERESERVE too small by %lld bytes.", -pad); + diag("dwarf: CIERESERVE too small by %lld bytes.", -pad); errorexit(); } strnput("", pad); @@ -2296,6 +2298,9 @@ dwarfemitdebugsections(void) vlong infoe; DWDie* die; + if(debug['w']) // disable dwarf + return; + // For diagnostic messages. newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes"); @@ -2348,11 +2353,11 @@ dwarfemitdebugsections(void) seek(cout, infoo, 0); writeinfo(); if (fwdcount > 0) { - diag("unresolved references after first dwarf info pass"); + diag("dwarf: unresolved references after first dwarf info pass"); errorexit(); } if (infoe != cpos()) { - diag("inconsistent second dwarf info pass"); + diag("dwarf: inconsistent second dwarf info pass"); errorexit(); } } @@ -2401,6 +2406,9 @@ vlong elfstrdbg[NElfStrDbg]; void dwarfaddshstrings(Sym *shstrtab) { + if(debug['w']) // disable dwarf + return; + elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev"); elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges"); elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame"); @@ -2420,6 +2428,9 @@ dwarfaddelfheaders(void) { ElfShdr *sh; + if(debug['w']) // disable dwarf + return; + sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]); sh->type = SHT_PROGBITS; sh->off = abbrevo; @@ -2488,6 +2499,9 @@ dwarfaddmachoheaders(void) vlong fakestart; int nsect; + if(debug['w']) // disable dwarf + return; + // Zero vsize segments won't be loaded in memory, even so they // have to be page aligned in the file. fakestart = abbrevo & ~0xfff; @@ -2562,6 +2576,9 @@ dwarfaddmachoheaders(void) void dwarfaddpeheaders(void) { + if(debug['w']) // disable dwarf + return; + newPEDWARFSection(".debug_abbrev", abbrevsize); newPEDWARFSection(".debug_line", linesize); newPEDWARFSection(".debug_frame", framesize); diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c index d8b0a6fc2..d6aa267c4 100644 --- a/src/cmd/ld/ldpe.c +++ b/src/cmd/ld/ldpe.c @@ -147,7 +147,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) goto bad; obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; obj->sect[i].name = (char*)obj->sect[i].sh.Name; - // TODO return error if found .cormeta .rsrc + // TODO return error if found .cormeta } // load string table Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); @@ -222,6 +222,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) etextp = s; } sect->sym = s; + if(strcmp(sect->name, ".rsrc") == 0) + setpersrc(sect->sym); } // load relocations @@ -259,6 +261,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn) rp->type = D_PCREL; rp->add = 0; break; + case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: rp->type = D_ADDR; // load addend from image diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index cd4608085..f69f5a35d 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -202,6 +202,7 @@ void addexport(void); void dostkcheck(void); void undef(void); void doweak(void); +void setpersrc(Sym*); int pathchar(void); void* mal(uint32); diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 01349bb10..0b12ac17b 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -17,6 +17,14 @@ static MachoSeg seg[16]; static MachoDebug xdebug[16]; static int nload, mload, nseg, ndebug, nsect; +// Amount of space left for adding load commands +// that refer to dynamic libraries. Because these have +// to go in the Mach-O header, we can't just pick a +// "big enough" header size. The initial header is +// one page, the non-dynamic library stuff takes +// up about 1300 bytes; we overestimate that as 2k. +static int load_budget = INITIAL_MACHO_HEADR - 2*1024; + void machoinit(void) { @@ -267,6 +275,17 @@ domacho(void) void machoadddynlib(char *lib) { + // Will need to store the library name rounded up + // and 24 bytes of header metadata. If not enough + // space, grab another page of initial space at the + // beginning of the output file. + load_budget -= (strlen(lib)+7)/8*8 + 24; + if(load_budget < 0) { + HEADR += 4096; + INITTEXT += 4096; + load_budget += 4096; + } + if(ndylib%32 == 0) { dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); if(dylib == nil) { @@ -463,8 +482,8 @@ asmbmacho(void) } a = machowrite(); - if(a > MACHORESERVE) - diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); + if(a > HEADR) + diag("HEADR too small: %d > %d", a, HEADR); } vlong diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h index 4cc7edc80..f55104150 100644 --- a/src/cmd/ld/macho.h +++ b/src/cmd/ld/macho.h @@ -63,7 +63,7 @@ void machoinit(void); * for Header, PHeaders, and SHeaders. * May waste some. */ -#define MACHORESERVE 3*1024 +#define INITIAL_MACHO_HEADR 4*1024 enum { MACHO_CPU_AMD64 = (1<<24)|7, diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c index 1c0c66538..91e15d343 100644 --- a/src/cmd/ld/pe.c +++ b/src/cmd/ld/pe.c @@ -34,6 +34,8 @@ static char dosstub[] = 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +static Sym *rsrcsym; + static char symnames[256]; static int nextsymoff; @@ -459,6 +461,48 @@ addsymtable(void) } void +setpersrc(Sym *sym) +{ + if(rsrcsym != nil) + diag("too many .rsrc sections"); + + rsrcsym = sym; +} + +void +addpersrc(void) +{ + IMAGE_SECTION_HEADER *h; + uchar *p; + uint32 val; + Reloc *r; + + if(rsrcsym == nil) + return; + + h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0); + h->Characteristics = IMAGE_SCN_MEM_READ| + IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA; + // relocation + for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) { + p = rsrcsym->p + r->off; + val = h->VirtualAddress + r->add; + // 32-bit little-endian + p[0] = val; + p[1] = val>>8; + p[2] = val>>16; + p[3] = val>>24; + } + ewrite(cout, rsrcsym->p, rsrcsym->size); + strnput("", h->SizeOfRawData - rsrcsym->size); + cflush(); + + // update data directory + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress; + dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize; +} + +void asmbpe(void) { IMAGE_SECTION_HEADER *t, *d; @@ -492,7 +536,9 @@ asmbpe(void) addexports(nextfileoff); addsymtable(); - + + addpersrc(); + fh.NumberOfSections = nsect; fh.TimeDateStamp = time(0); fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED| diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h index 2180fb88c..7aa938829 100644 --- a/src/cmd/ld/pe.h +++ b/src/cmd/ld/pe.h @@ -175,3 +175,5 @@ typedef struct { uint32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[16]; } PE64_IMAGE_OPTIONAL_HEADER; + +void setpersrc(Sym *sym); |