summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5a/a.h1
-rw-r--r--src/cmd/5g/cgen.c104
-rw-r--r--src/cmd/5g/cgen64.c12
-rw-r--r--src/cmd/5g/galign.c2
-rw-r--r--src/cmd/5g/ggen.c5
-rw-r--r--src/cmd/5g/opt.h2
-rw-r--r--src/cmd/5g/peep.c229
-rw-r--r--src/cmd/5g/reg.c142
-rw-r--r--src/cmd/5l/Makefile1
-rw-r--r--src/cmd/5l/asm.c13
-rw-r--r--src/cmd/5l/doc.go5
-rw-r--r--src/cmd/5l/l.h2
-rw-r--r--src/cmd/5l/noop.c14
-rw-r--r--src/cmd/5l/obj.c10
-rw-r--r--src/cmd/5l/optab.c4
-rw-r--r--src/cmd/5l/span.c2
-rw-r--r--src/cmd/6a/a.h1
-rw-r--r--src/cmd/6g/cgen.c3
-rw-r--r--src/cmd/6g/galign.c2
-rw-r--r--src/cmd/6g/gsubr.c2
-rw-r--r--src/cmd/6g/reg.c2
-rw-r--r--src/cmd/6l/Makefile3
-rw-r--r--src/cmd/6l/asm.c45
-rw-r--r--src/cmd/6l/doc.go2
-rw-r--r--src/cmd/6l/l.h3
-rw-r--r--src/cmd/6l/obj.c21
-rw-r--r--src/cmd/6l/pass.c38
-rw-r--r--src/cmd/8a/a.h1
-rw-r--r--src/cmd/8g/cgen.c2
-rw-r--r--src/cmd/8g/galign.c2
-rw-r--r--src/cmd/8g/reg.c1
-rw-r--r--src/cmd/8l/Makefile1
-rw-r--r--src/cmd/8l/asm.c21
-rw-r--r--src/cmd/8l/doc.go2
-rw-r--r--src/cmd/8l/l.h2
-rw-r--r--src/cmd/8l/obj.c5
-rw-r--r--src/cmd/8l/pass.c9
-rw-r--r--src/cmd/cc/Makefile2
-rw-r--r--src/cmd/cc/cc.h7
-rw-r--r--src/cmd/cc/dcl.c6
-rw-r--r--src/cmd/cc/dpchk.c1
-rw-r--r--src/cmd/cc/godefs.c387
-rw-r--r--src/cmd/cc/lex.c24
-rw-r--r--src/cmd/cc/lexbody43
-rw-r--r--src/cmd/cc/pgen.c3
-rw-r--r--src/cmd/cc/pickle.c298
-rw-r--r--src/cmd/cgo/ast.go21
-rw-r--r--src/cmd/cgo/doc.go9
-rw-r--r--src/cmd/cgo/gcc.go144
-rw-r--r--src/cmd/cgo/main.go32
-rw-r--r--src/cmd/cgo/out.go21
-rw-r--r--src/cmd/ebnflint/ebnflint.go3
-rw-r--r--src/cmd/gc/align.c2
-rw-r--r--src/cmd/gc/builtin.c.boot6
-rw-r--r--src/cmd/gc/const.c12
-rw-r--r--src/cmd/gc/cplx.c6
-rw-r--r--src/cmd/gc/go.h8
-rw-r--r--src/cmd/gc/go.y15
-rw-r--r--src/cmd/gc/lex.c2
-rw-r--r--src/cmd/gc/print.c5
-rw-r--r--src/cmd/gc/range.c13
-rw-r--r--src/cmd/gc/reflect.c7
-rw-r--r--src/cmd/gc/runtime.go7
-rw-r--r--src/cmd/gc/select.c217
-rw-r--r--src/cmd/gc/sinit.c4
-rw-r--r--src/cmd/gc/subr.c8
-rw-r--r--src/cmd/gc/typecheck.c113
-rw-r--r--src/cmd/gc/walk.c24
-rw-r--r--src/cmd/godefs/main.c2
-rw-r--r--src/cmd/godefs/stabs.c81
-rw-r--r--src/cmd/godoc/doc.go5
-rw-r--r--src/cmd/godoc/format.go68
-rw-r--r--src/cmd/godoc/godoc.go120
-rw-r--r--src/cmd/godoc/index.go151
-rw-r--r--src/cmd/godoc/main.go14
-rwxr-xr-xsrc/cmd/godoc/snippet.go2
-rw-r--r--src/cmd/godoc/spec.go3
-rw-r--r--src/cmd/godoc/utils.go62
-rw-r--r--src/cmd/gofmt/rewrite.go4
-rw-r--r--src/cmd/goinstall/main.go3
-rw-r--r--src/cmd/gopack/ar.c1
-rwxr-xr-xsrc/cmd/gotest/gotest6
-rw-r--r--src/cmd/govet/govet.go2
-rw-r--r--src/cmd/ld/data.c29
-rw-r--r--src/cmd/ld/dwarf.c176
-rw-r--r--src/cmd/ld/dwarf.h1
-rw-r--r--src/cmd/ld/ldpe.c406
-rw-r--r--src/cmd/ld/lib.c4
-rw-r--r--src/cmd/ld/lib.h1
-rw-r--r--src/cmd/ld/pe.c419
-rw-r--r--src/cmd/ld/pe.h50
91 files changed, 2639 insertions, 1137 deletions
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index bc4f433e1..550b61dcf 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -54,7 +54,6 @@ typedef struct Hist Hist;
#define NSYMB 8192
#define BUFSIZ 8192
#define HISTSZ 20
-#define NHUNK 10000
#define EOF (-1)
#define IGN (-2)
#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 1328f4be6..032409bae 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -169,7 +169,7 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
- case OCMPLX:
+ case OCOMPLEX:
fatal("unexpected complex");
break;
@@ -567,7 +567,8 @@ agen(Node *n, Node *res)
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
- } else if(nl->addable) {
+ } else
+ if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
@@ -671,7 +672,8 @@ agen(Node *n, Node *res)
p1 = gins(AMOVW, N, &n3);
datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
p1->from.type = D_CONST;
- } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+ } else
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -813,6 +815,28 @@ agenr(Node *n, Node *a, Node *res)
agen(n, a);
}
+void
+gencmp0(Node *n, Type *t, int o, Prog *to)
+{
+ Node n1, n2, n3;
+ int a;
+
+ regalloc(&n1, t, N);
+ cgen(n, &n1);
+ a = optoas(OCMP, t);
+ if(a != ACMP) {
+ nodconst(&n2, t, 0);
+ regalloc(&n3, t, N);
+ gmove(&n2, &n3);
+ gcmp(a, &n1, &n3);
+ regfree(&n3);
+ } else
+ gins(ATST, &n1, N);
+ a = optoas(o, t);
+ patch(gbranch(a, t), to);
+ regfree(&n1);
+}
+
/*
* generate:
* if(n == true) goto to;
@@ -855,19 +879,10 @@ bgen(Node *n, int true, Prog *to)
switch(n->op) {
default:
- def:
- regalloc(&n1, n->type, N);
- cgen(n, &n1);
- nodconst(&n2, n->type, 0);
- regalloc(&n3, n->type, N);
- gmove(&n2, &n3);
- gcmp(optoas(OCMP, n->type), &n1, &n3);
- a = ABNE;
+ a = ONE;
if(!true)
- a = ABEQ;
- patch(gbranch(a, n->type), to);
- regfree(&n1);
- regfree(&n3);
+ a = OEQ;
+ gencmp0(n, n->type, a, to);
goto ret;
case OLITERAL:
@@ -876,23 +891,6 @@ bgen(Node *n, int true, Prog *to)
patch(gbranch(AB, T), to);
goto ret;
- case ONAME:
- if(n->addable == 0)
- goto def;
- nodconst(&n1, n->type, 0);
- regalloc(&n2, n->type, N);
- regalloc(&n3, n->type, N);
- gmove(&n1, &n2);
- cgen(n, &n3);
- gcmp(optoas(OCMP, n->type), &n2, &n3);
- a = ABNE;
- if(!true)
- a = ABEQ;
- patch(gbranch(a, n->type), to);
- regfree(&n2);
- regfree(&n3);
- goto ret;
-
case OANDAND:
if(!true)
goto caseor;
@@ -975,6 +973,16 @@ bgen(Node *n, int true, Prog *to)
yyerror("illegal array comparison");
break;
}
+
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = Array_array;
+ gencmp0(&n2, types[tptr], a, to);
+ regfree(&n1);
+ break;
+
a = optoas(a, types[tptr]);
regalloc(&n1, types[tptr], N);
regalloc(&n3, types[tptr], N);
@@ -1000,6 +1008,16 @@ bgen(Node *n, int true, Prog *to)
yyerror("illegal interface comparison");
break;
}
+
+ regalloc(&n1, types[tptr], N);
+ agen(nl, &n1);
+ n2 = n1;
+ n2.op = OINDREG;
+ n2.xoffset = 0;
+ gencmp0(&n2, types[tptr], a, to);
+ regfree(&n1);
+ break;
+
a = optoas(a, types[tptr]);
regalloc(&n1, types[tptr], N);
regalloc(&n3, types[tptr], N);
@@ -1039,6 +1057,17 @@ bgen(Node *n, int true, Prog *to)
break;
}
+ if(nr->op == OLITERAL) {
+ if(nr->val.ctype == CTINT && mpgetfix(nr->val.u.xval) == 0) {
+ gencmp0(nl, nl->type, a, to);
+ break;
+ }
+ if(nr->val.ctype == CTNIL) {
+ gencmp0(nl, nl->type, a, to);
+ break;
+ }
+ }
+
a = optoas(a, nr->type);
if(nr->ullman >= UINF) {
@@ -1063,11 +1092,17 @@ bgen(Node *n, int true, Prog *to)
break;
}
+ tempname(&n3, nl->type);
+ cgen(nl, &n3);
+
+ tempname(&tmp, nr->type);
+ cgen(nr, &tmp);
+
regalloc(&n1, nl->type, N);
- cgen(nl, &n1);
+ gmove(&n3, &n1);
regalloc(&n2, nr->type, N);
- cgen(nr, &n2);
+ gmove(&tmp, &n2);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
if(isfloat[nl->type->etype]) {
@@ -1080,7 +1115,6 @@ bgen(Node *n, int true, Prog *to)
} else {
patch(gbranch(a, nr->type), to);
}
-
regfree(&n1);
regfree(&n2);
break;
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index 716ec5ed5..78f2f4aeb 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -233,8 +233,7 @@ cgen64(Node *n, Node *res)
// shift is >= 1<<32
split64(r, &cl, &ch);
gmove(&ch, &s);
- p1 = gins(AMOVW, &s, &s);
- p1->scond |= C_SBIT;
+ p1 = gins(ATST, &s, N);
p6 = gbranch(ABNE, T);
gmove(&cl, &s);
splitclean();
@@ -242,8 +241,7 @@ cgen64(Node *n, Node *res)
gmove(r, &s);
p6 = P;
}
- p1 = gins(AMOVW, &s, &s);
- p1->scond |= C_SBIT;
+ p1 = gins(ATST, &s, N);
// shift == 0
p1 = gins(AMOVW, &bl, &al);
@@ -390,8 +388,7 @@ olsh_break:
// shift is >= 1<<32
split64(r, &cl, &ch);
gmove(&ch, &s);
- p1 = gins(AMOVW, &s, &s);
- p1->scond |= C_SBIT;
+ p1 = gins(ATST, &s, N);
p6 = gbranch(ABNE, T);
gmove(&cl, &s);
splitclean();
@@ -399,8 +396,7 @@ olsh_break:
gmove(r, &s);
p6 = P;
}
- p1 = gins(AMOVW, &s, &s);
- p1->scond |= C_SBIT;
+ p1 = gins(ATST, &s, N);
// shift == 0
p1 = gins(AMOVW, &bl, &al);
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 9c8760aea..0fece9a08 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -17,8 +17,6 @@ Typedef typedefs[] =
"int", TINT, TINT32,
"uint", TUINT, TUINT32,
"uintptr", TUINTPTR, TUINT32,
- "float", TFLOAT, TFLOAT32,
- "complex", TCOMPLEX, TCOMPLEX64,
0
};
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 42a89415d..182d7f147 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -172,7 +172,7 @@ ginscall(Node *f, int proc)
p->to.reg = REGSP;
p->to.offset = 8;
- nodconst(&con, types[TINT32], argsize(f->type) + 4);
+ nodconst(&con, types[TINT32], argsize(f->type));
gins(AMOVW, &con, &r);
p = gins(AMOVW, &r, N);
p->to.type = D_OREG;
@@ -595,8 +595,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
}
// test for shift being 0
- p1 = gins(AMOVW, &n1, &n1);
- p1->scond |= C_SBIT;
+ p1 = gins(ATST, &n1, N);
p3 = gbranch(ABEQ, T);
// test and fix up large shifts
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 9a4e17571..7a0070fc9 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -128,7 +128,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Reg *r, Adr *a, int);
+Bits mkvar(Reg *r, Adr *a);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
index 32333e8a9..f619a6206 100644
--- a/src/cmd/5g/peep.c
+++ b/src/cmd/5g/peep.c
@@ -89,11 +89,11 @@ loop1:
/*
* elide shift into D_SHIFT operand of subsequent instruction
*/
- if(shiftprop(r)) {
- excise(r);
- t++;
- break;
- }
+// if(shiftprop(r)) {
+// excise(r);
+// t++;
+// break;
+// }
break;
case AMOVW:
@@ -101,10 +101,10 @@ loop1:
case AMOVD:
if(!regtyp(&p->to))
break;
- if(isdconst(&p->from)) {
- constprop(&p->from, &p->to, r->s1);
- break;
- }
+// if(isdconst(&p->from)) {
+// constprop(&p->from, &p->to, r->s1);
+// break;
+// }
if(!regtyp(&p->from))
break;
if(p->from.type != p->to.type)
@@ -166,87 +166,89 @@ loop1:
excise(r1);
}
- for(r=firstr; r!=R; r=r->link) {
- p = r->prog;
- switch(p->as) {
- case AMOVW:
- case AMOVB:
- case AMOVBU:
- if(p->from.type == D_OREG && p->from.offset == 0)
- xtramodes(r, &p->from);
- else if(p->to.type == D_OREG && p->to.offset == 0)
- xtramodes(r, &p->to);
- else
- continue;
- break;
- case ACMP:
- /*
- * elide CMP $0,x if calculation of x can set condition codes
- */
- if(isdconst(&p->from) || p->from.offset != 0)
- continue;
- r2 = r->s1;
- if(r2 == R)
- continue;
- t = r2->prog->as;
- switch(t) {
- default:
- continue;
- case ABEQ:
- case ABNE:
- case ABMI:
- case ABPL:
- break;
- case ABGE:
- t = ABPL;
- break;
- case ABLT:
- t = ABMI;
- break;
- case ABHI:
- t = ABNE;
- break;
- case ABLS:
- t = ABEQ;
- break;
- }
- r1 = r;
- do
- r1 = uniqp(r1);
- while (r1 != R && r1->prog->as == ANOP);
- if(r1 == R)
- continue;
- p1 = r1->prog;
- if(p1->to.type != D_REG)
- continue;
- if(p1->to.reg != p->reg)
- if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
- continue;
- switch(p1->as) {
- default:
- continue;
- case AMOVW:
- if(p1->from.type != D_REG)
- continue;
- case AAND:
- case AEOR:
- case AORR:
- case ABIC:
- case AMVN:
- case ASUB:
- case ARSB:
- case AADD:
- case AADC:
- case ASBC:
- case ARSC:
- break;
- }
- p1->scond |= C_SBIT;
- r2->prog->as = t;
- excise(r);
- continue;
- }
- }
+// for(r=firstr; r!=R; r=r->link) {
+// p = r->prog;
+// switch(p->as) {
+// case AMOVW:
+// case AMOVB:
+// case AMOVBU:
+// if(p->from.type == D_OREG && p->from.offset == 0)
+// xtramodes(r, &p->from);
+// else
+// if(p->to.type == D_OREG && p->to.offset == 0)
+// xtramodes(r, &p->to);
+// else
+// continue;
+// break;
+// case ACMP:
+// /*
+// * elide CMP $0,x if calculation of x can set condition codes
+// */
+// if(isdconst(&p->from) || p->from.offset != 0)
+// continue;
+// r2 = r->s1;
+// if(r2 == R)
+// continue;
+// t = r2->prog->as;
+// switch(t) {
+// default:
+// continue;
+// case ABEQ:
+// case ABNE:
+// case ABMI:
+// case ABPL:
+// break;
+// case ABGE:
+// t = ABPL;
+// break;
+// case ABLT:
+// t = ABMI;
+// break;
+// case ABHI:
+// t = ABNE;
+// break;
+// case ABLS:
+// t = ABEQ;
+// break;
+// }
+// r1 = r;
+// do
+// r1 = uniqp(r1);
+// while (r1 != R && r1->prog->as == ANOP);
+// if(r1 == R)
+// continue;
+// p1 = r1->prog;
+// if(p1->to.type != D_REG)
+// continue;
+// if(p1->to.reg != p->reg)
+// if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+// continue;
+//
+// switch(p1->as) {
+// default:
+// continue;
+// case AMOVW:
+// if(p1->from.type != D_REG)
+// continue;
+// case AAND:
+// case AEOR:
+// case AORR:
+// case ABIC:
+// case AMVN:
+// case ASUB:
+// case ARSB:
+// case AADD:
+// case AADC:
+// case ASBC:
+// case ARSC:
+// break;
+// }
+// p1->scond |= C_SBIT;
+// r2->prog->as = t;
+// excise(r);
+// continue;
+// }
+// }
predicate();
}
@@ -331,10 +333,13 @@ subprop(Reg *r0)
case ABL:
return 0;
- case ACMP:
+ case AMULLU:
+ case AMULA:
+
case ACMN:
case AADD:
case ASUB:
+ case ASBC:
case ARSB:
case ASLL:
case ASRL:
@@ -342,12 +347,14 @@ subprop(Reg *r0)
case AORR:
case AAND:
case AEOR:
+ case AMVN:
case AMUL:
+ case AMULU:
case ADIV:
case ADIVU:
+ case AMOD:
+ case AMODU:
- case ACMPF:
- case ACMPD:
case AADDD:
case AADDF:
case ASUBD:
@@ -622,8 +629,8 @@ shiftprop(Reg *r)
case AADC:
case AORR:
case ASUB:
- case ARSB:
case ASBC:
+ case ARSB:
case ARSC:
if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
if(p1->from.type != D_REG)
@@ -648,6 +655,7 @@ shiftprop(Reg *r)
print("\t=>%P", p1);
}
case ABIC:
+ case ATST:
case ACMP:
case ACMN:
if(p1->reg == n)
@@ -922,8 +930,7 @@ copyu(Prog *p, Adr *v, Adr *s)
switch(p->as) {
default:
- if(debug['P'])
- print(" (?)");
+ print("copyu: cant find %A\n", p->as);
return 2;
case AMOVM:
@@ -983,7 +990,7 @@ copyu(Prog *p, Adr *v, Adr *s)
return 2;
} else {
if(p->to.reg == v->reg)
- return 2;
+ return 2;
}
}
if(s != A) {
@@ -1005,8 +1012,14 @@ copyu(Prog *p, Adr *v, Adr *s)
return 1;
return 0;
+ case AMULLU: /* read, read, write, write */
+ case AMULA:
+ return 2;
+
case AADD: /* read, read, write */
+ case AADC:
case ASUB:
+ case ASBC:
case ARSB:
case ASLL:
case ASRL:
@@ -1014,9 +1027,13 @@ copyu(Prog *p, Adr *v, Adr *s)
case AORR:
case AAND:
case AEOR:
+ case AMVN:
case AMUL:
+ case AMULU:
case ADIV:
case ADIVU:
+ case AMOD:
+ case AMODU:
case AADDF:
case AADDD:
case ASUBF:
@@ -1028,6 +1045,7 @@ copyu(Prog *p, Adr *v, Adr *s)
case ACMPF:
case ACMPD:
+ case ATST:
case ACMP:
case ACMN:
case ACASE:
@@ -1138,9 +1156,13 @@ a2type(Prog *p)
switch(p->as) {
+ case ATST:
case ACMP:
case ACMN:
+ case AMULLU:
+ case AMULA:
+
case AADD:
case ASUB:
case ARSB:
@@ -1150,9 +1172,13 @@ a2type(Prog *p)
case AORR:
case AAND:
case AEOR:
+ case AMVN:
case AMUL:
+ case AMULU:
case ADIV:
case ADIVU:
+ case AMOD:
+ case AMODU:
return D_REG;
case ACMPF:
@@ -1369,12 +1395,15 @@ int
modifiescpsr(Prog *p)
{
switch(p->as) {
- case ATST:
+ case AMULLU:
+ case AMULA:
+ case AMULU:
+ case ADIVU:
+
case ATEQ:
case ACMN:
+ case ATST:
case ACMP:
- case AMULU:
- case ADIVU:
case AMUL:
case ADIV:
case AMOD:
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 5011e75cc..eaf02b237 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -83,7 +83,7 @@ setoutvar(void)
n = nodarg(t, 1);
a = zprog.from;
naddr(n, &a, 0);
- bit = mkvar(R, &a, 0);
+ bit = mkvar(R, &a);
for(z=0; z<BITS; z++)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
@@ -137,14 +137,13 @@ regopt(Prog *firstp)
uint32 vreg;
Bits bit;
-return; // disabled for the moment
if(first == 0) {
fmtinstall('Q', Qconv);
}
first++;
if(debug['K']) {
- if(first != 20)
+ if(first != 13)
return;
// debug['R'] = 2;
// debug['P'] = 2;
@@ -166,7 +165,7 @@ return; // disabled for the moment
firstr = R;
lastr = R;
nvar = 0;
- regbits = 0;
+ regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
params.b[z] = 0;
@@ -221,14 +220,14 @@ return; // disabled for the moment
/*
* left side always read
*/
- bit = mkvar(r, &p->from, p->as==AMOVW);
+ bit = mkvar(r, &p->from);
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
/*
* right side depends on opcode
*/
- bit = mkvar(r, &p->to, 0);
+ bit = mkvar(r, &p->to);
if(bany(&bit))
switch(p->as) {
default:
@@ -254,8 +253,7 @@ return; // disabled for the moment
* funny
*/
case ABL:
- for(z=0; z<BITS; z++)
- addrs.b[z] |= bit.b[z];
+ setaddrs(bit);
break;
}
@@ -273,6 +271,18 @@ return; // disabled for the moment
if(firstr == R)
return;
+ for(i=0; i<nvar; i++) {
+ Var *v = var+i;
+ if(v->addr) {
+ bit = blsh(i);
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ }
+
+// print("bit=%2d addr=%d et=%-6E w=%-2d s=%S + %lld\n",
+// i, v->addr, v->etype, v->width, v->sym, v->offset);
+ }
+
/*
* pass 2
* turn branch references to pointers
@@ -298,6 +308,7 @@ return; // disabled for the moment
if(debug['R']) {
p = firstr->prog;
print("\n%L %D\n", p->lineno, &p->from);
+ print(" addr = %Q\n", addrs);
}
/*
@@ -361,6 +372,7 @@ loop2:
r->refahead.b[z] | r->calahead.b[z] |
r->refbehind.b[z] | r->calbehind.b[z] |
r->use1.b[z] | r->use2.b[z];
+ bit.b[z] &= ~addrs.b[z];
}
if(bany(&bit)) {
@@ -486,18 +498,61 @@ brk:
* last pass
* eliminate nops
* free aux structures
+ * adjust the stack pointer
+ * MOVW.W R1,-12(R13) <<- start
+ * MOVW R0,R1
+ * MOVW R1,8(R13)
+ * MOVW $0,R1
+ * MOVW R1,4(R13)
+ * BL ,runtime.newproc+0(SB)
+ * MOVW &ft+-32(SP),R7 <<- adjust
+ * MOVW &j+-40(SP),R6 <<- adjust
+ * MOVW autotmp_0003+-24(SP),R5 <<- adjust
+ * MOVW $12(R13),R13 <<- finish
*/
+ vreg = 0;
for(p = firstp; p != P; p = p->link) {
while(p->link != P && p->link->as == ANOP)
p->link = p->link->link;
if(p->to.type == D_BRANCH)
while(p->to.branch != P && p->to.branch->as == ANOP)
p->to.branch = p->to.branch->link;
+ if(p->as == AMOVW && p->to.reg == 13) {
+ if(p->scond & C_WBIT) {
+ vreg = -p->to.offset; // in adjust region
+// print("%P adjusting %d\n", p, vreg);
+ continue;
+ }
+ if(p->from.type == D_CONST && p->to.type == D_REG) {
+ if(p->from.offset != vreg)
+ print("in and out different\n");
+// print("%P finish %d\n", p, vreg);
+ vreg = 0; // done adjust region
+ continue;
+ }
+
+// print("%P %d %d from type\n", p, p->from.type, D_CONST);
+// print("%P %d %d to type\n\n", p, p->to.type, D_REG);
+ }
+
+ if(p->as == AMOVW && vreg != 0) {
+ if(p->from.sym != S)
+ if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
+ p->from.offset += vreg;
+// print("%P adjusting from %d %d\n", p, vreg, p->from.type);
+ }
+ if(p->to.sym != S)
+ if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
+ p->to.offset += vreg;
+// print("%P adjusting to %d %d\n", p, vreg, p->from.type);
+ }
+ }
}
if(r1 != R) {
r1->link = freer;
freer = firstr;
}
+
}
void
@@ -557,24 +612,31 @@ addmove(Reg *r, int bn, int rn, int f)
if(a->etype == TARRAY || a->sym == S)
a->type = D_CONST;
+ if(v->addr)
+ fatal("addmove: shouldnt be doing this %A\n", a);
+
switch(v->etype) {
default:
print("What is this %E\n", v->etype);
- case TINT32:
- case TUINT32:
- case TPTR32:
- case TBOOL:
- p1->as = AMOVW;
- break;
case TINT8:
- case TUINT8:
p1->as = AMOVB;
break;
+ case TBOOL:
+ case TUINT8:
+ p1->as = AMOVBU;
+ break;
case TINT16:
- case TUINT16:
p1->as = AMOVH;
break;
+ case TUINT16:
+ p1->as = AMOVHU;
+ break;
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ p1->as = AMOVW;
+ break;
case TFLOAT32:
p1->as = AMOVF;
break;
@@ -598,7 +660,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->type = D_FREG;
a->reg = rn-NREG;
}
- if(v->etype == TUINT8)
+ if(v->etype == TUINT8 || v->etype == TBOOL)
p1->as = AMOVBU;
if(v->etype == TUINT16)
p1->as = AMOVHU;
@@ -622,7 +684,7 @@ overlap(int32 o1, int w1, int32 o2, int w2)
}
Bits
-mkvar(Reg *r, Adr *a, int docon)
+mkvar(Reg *r, Adr *a)
{
Var *v;
int i, t, n, et, z, w, flag;
@@ -634,29 +696,33 @@ mkvar(Reg *r, Adr *a, int docon)
t = a->type;
n = D_NONE;
+ flag = 0;
+// if(a->pun)
+// flag = 1;
+
switch(t) {
default:
print("type %d %d %D\n", t, a->name, a);
goto none;
- case D_CONST:
- if(a->reg != NREG)
- r->regu |= RtoB(a->reg);
- // fallthrough
-
case D_NONE:
case D_FCONST:
case D_BRANCH:
- goto none;
+ break;
+
+ case D_CONST:
+ flag = 1;
+ goto onereg;
case D_REGREG:
if(a->offset != NREG)
r->regu |= RtoB(a->offset);
- // fallthrough
+ goto onereg;
case D_REG:
case D_SHIFT:
case D_OREG:
+ onereg:
if(a->reg != NREG)
r->regu |= RtoB(a->reg);
break;
@@ -679,10 +745,6 @@ mkvar(Reg *r, Adr *a, int docon)
break;
}
- flag = 0;
-// if(a->pun)
-// flag = 1;
-
s = a->sym;
if(s == S)
goto none;
@@ -737,7 +799,6 @@ mkvar(Reg *r, Adr *a, int docon)
if(debug['R'])
print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
-out:
bit = blsh(i);
if(n == D_EXTERN || n == D_STATIC)
for(z=0; z<BITS; z++)
@@ -746,22 +807,6 @@ out:
for(z=0; z<BITS; z++)
params.b[z] |= bit.b[z];
-// if(t == D_CONST) {
-// if(s == S) {
-// for(z=0; z<BITS; z++)
-// consts.b[z] |= bit.b[z];
-// return bit;
-// }
-// if(et != TARRAY)
-// for(z=0; z<BITS; z++)
-// addrs.b[z] |= bit.b[z];
-// for(z=0; z<BITS; z++)
-// params.b[z] |= bit.b[z];
-// return bit;
-// }
-// if(t != D_OREG)
-// goto none;
-
return bit;
none:
@@ -1021,7 +1066,6 @@ allreg(uint32 b, Rgn *r)
case TFLOAT32:
case TFLOAT64:
- case TFLOAT:
i = BtoF(~b);
if(i && r->cost >= 0) {
r->regno = i+NREG;
@@ -1195,6 +1239,7 @@ paint3(Reg *r, int bn, int32 rb, int rn)
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
addmove(r, bn, rn, 0);
+
for(;;) {
r->act.b[z] |= bb;
p = r->prog;
@@ -1243,6 +1288,9 @@ void
addreg(Adr *a, int rn)
{
+ if(a->type == D_CONST)
+ fatal("addreg: cant do this %D %d\n", a, rn);
+
a->sym = 0;
a->name = D_NONE;
a->type = D_REG;
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index 71798724b..c11ebe990 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -14,6 +14,7 @@ OFILES=\
enam.$O\
ldelf.$O\
ldmacho.$O\
+ ldpe.$O\
lib.$O\
list.$O\
noop.$O\
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 7ceea59b6..34565629f 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -448,7 +448,9 @@ asmb(void)
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
- elfinterp(sh, startva, linuxdynld);
+ if(interpreter == nil)
+ interpreter = linuxdynld;
+ elfinterp(sh, startva, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
@@ -793,7 +795,8 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
rt = 0;
if(p->as == AMOVW || p->as == AMVN)
r = 0;
- else if(r == NREG)
+ else
+ if(r == NREG)
r = rt;
o1 |= rf | (r<<16) | (rt<<12);
break;
@@ -1558,6 +1561,10 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= (p->from.reg<<16);
o1 |= (p->to.reg<<12);
break;
+ case 90: /* tst reg */
+ o1 = oprrr(ACMP+AEND, p->scond);
+ o1 |= p->from.reg<<16;
+ break;
}
out[0] = o1;
@@ -1709,6 +1716,8 @@ oprrr(int a, int sc)
return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
case AMOVFW+AEND: // copy FtoW
return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
+ case ACMP+AEND: // cmp imm
+ return o | (0x3<<24) | (0x5<<20);
}
diag("bad rrr %d", a);
prasm(curp);
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
index 6f7408116..d266b9233 100644
--- a/src/cmd/5l/doc.go
+++ b/src/cmd/5l/doc.go
@@ -20,6 +20,11 @@ Original options are listed in the link above.
Options new in this version:
+-F
+ Force use of software floating point.
+ Also implied by setting GOARM=5 in the environment.
+-I interpreter
+ Set the ELF dynamic linker to use.
-L dir1 -L dir2
Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_arm.
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index 4e7ccea88..c31028416 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -276,7 +276,6 @@ enum
STRINGSZ = 200,
NHASH = 10007,
- NHUNK = 100000,
MINSIZ = 64,
NENT = 100,
MAXIO = 8192,
@@ -333,6 +332,7 @@ EXTERN Oprang thumboprange[ALAST];
EXTERN char* outfile;
EXTERN int32 pc;
EXTERN uchar repop[ALAST];
+EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 5def0d3f1..a9439c27a 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -330,23 +330,23 @@ noops(void)
p->from.reg = 1;
p->reg = 2;
}
-
+
// MOVW.LO $autosize, R1
p = appendp(p);
p->as = AMOVW;
p->scond = C_SCOND_LO;
p->from.type = D_CONST;
- p->from.offset = 0;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ p->from.offset = autosize+160;
p->to.type = D_REG;
p->to.reg = 1;
- // MOVW.LO $args +4, R2
- // also need to store the extra 4 bytes.
+ // MOVW.LO $args, R2
p = appendp(p);
p->as = AMOVW;
p->scond = C_SCOND_LO;
p->from.type = D_CONST;
- p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4;
+ p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
p->to.type = D_REG;
p->to.reg = 2;
@@ -391,12 +391,12 @@ noops(void)
p->to.type = D_REG;
p->to.reg = 1;
- // MOVW $args +4, R2
+ // MOVW $args, R2
// also need to store the extra 4 bytes.
p = appendp(p);
p->as = AMOVW;
p->from.type = D_CONST;
- p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4;
+ p->from.offset = (cursym->text->to.offset2 + 3) & ~3;
p->to.type = D_REG;
p->to.reg = 2;
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index cb9ad9805..5b778d777 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -61,7 +61,7 @@ linkername[] =
void
usage(void)
{
- fprint(2, "usage: 5l [-E entry] [-H head] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n");
+ fprint(2, "usage: 5l [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-D data] [-R rnd] [-r path] [-o out] main.5\n");
errorexit();
}
@@ -69,6 +69,7 @@ void
main(int argc, char *argv[])
{
int c, i;
+ char *p;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -80,6 +81,10 @@ main(int argc, char *argv[])
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
+
+ p = getenv("GOARM");
+ if(p != nil && strcmp(p, "5") == 0)
+ debug['F'] = 1;
ARGBEGIN {
default:
@@ -95,6 +100,9 @@ main(int argc, char *argv[])
case 'E':
INITENTRY = EARGF(usage());
break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
case 'L':
Lflag(EARGF(usage()));
break;
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 96b216837..9ad0193ac 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -64,7 +64,7 @@ Optab optab[] =
{ AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
{ ABL, C_NONE, C_NONE, C_ROREG, 7, 8, 0 },
{ ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 },
- { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
+ { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 },
{ ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 },
{ ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 },
@@ -251,5 +251,7 @@ Optab optab[] =
{ AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
{ AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
+ { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 },
+
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index be0f5e8b3..220140f43 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -962,7 +962,6 @@ buildop(void)
oprange[ABIC] = oprange[r];
break;
case ACMP:
- oprange[ATST] = oprange[r];
oprange[ATEQ] = oprange[r];
oprange[ACMN] = oprange[r];
break;
@@ -1055,6 +1054,7 @@ buildop(void)
case ALDREX:
case ASTREX:
+ case ATST:
break;
}
}
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index 9030081ca..2d4272646 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -57,7 +57,6 @@ typedef struct Gen2 Gen2;
#define NSYMB 500
#define BUFSIZ 8192
#define HISTSZ 20
-#define NHUNK 10000
#define EOF (-1)
#define IGN (-2)
#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index d4d22fd61..47f3374f5 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -431,9 +431,6 @@ agen(Node *n, Node *res)
if(n == N || n->type == T)
return;
- if(!isptr[res->type->etype] && res->type->etype != TUINTPTR)
- fatal("agen: not tptr: %T", res->type);
-
while(n->op == OCONVNOP)
n = n->left;
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index bdfc9947e..97bfb58e8 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -17,8 +17,6 @@ Typedef typedefs[] =
"int", TINT, TINT32,
"uint", TUINT, TUINT32,
"uintptr", TUINTPTR, TUINT64,
- "float", TFLOAT, TFLOAT32,
- "complex", TCOMPLEX, TCOMPLEX64,
0
};
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index ebb61ea94..c3dac1fdc 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -246,7 +246,7 @@ anyregalloc(void)
{
int i, j;
- for(i=D_AL; i<=D_DI; i++) {
+ for(i=D_AX; i<=D_R15; i++) {
if(reg[i] == 0)
goto ok;
for(j=0; j<nelem(resvd); j++)
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 464627066..1e1d64c59 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -748,7 +748,6 @@ addmove(Reg *r, int bn, int rn, int f)
case TPTR64:
p1->as = AMOVQ;
break;
- case TFLOAT:
case TFLOAT32:
p1->as = AMOVSS;
break;
@@ -1180,7 +1179,6 @@ allreg(uint32 b, Rgn *r)
case TFLOAT32:
case TFLOAT64:
- case TFLOAT:
i = BtoF(~b);
if(i && r->cost > 0) {
r->regno = i;
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index fba1b42ae..abe204d4f 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -16,12 +16,14 @@ OFILES=\
go.$O\
ldelf.$O\
ldmacho.$O\
+ ldpe.$O\
lib.$O\
list.$O\
macho.$O\
obj.$O\
optab.$O\
pass.$O\
+ pe.$O\
prof.$O\
span.$O\
symtab.$O\
@@ -33,6 +35,7 @@ HFILES=\
../ld/elf.h\
../ld/macho.h\
../ld/dwarf.h\
+ ../ld/pe.h\
include ../../Make.ccmd
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index 9726d227c..d6ffa4ff9 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -35,6 +35,7 @@
#include "../ld/elf.h"
#include "../ld/dwarf.h"
#include "../ld/macho.h"
+#include "../ld/pe.h"
#define Dbufslop 100
@@ -205,15 +206,16 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_X86_64_GOTPCREL:
if(targ->dynimpname == nil || targ->dynexport) {
// have symbol
- // turn MOVQ of GOT entry into LEAQ of symbol itself
- if(r->off < 2 || s->p[r->off-2] != 0x8b) {
- diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+ if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ r->add += 4;
return;
}
- s->p[r->off-2] = 0x8d;
- r->type = D_PCREL;
- r->add += 4;
- return;
+ // fall back to using GOT and hope for the best (CMOV*)
+ // TODO: just needs relocation, no need to put in .dynsym
+ targ->dynimpname = targ->name;
}
addgotsym(targ);
r->type = D_PCREL;
@@ -782,6 +784,8 @@ asmb(void)
if(!debug['d'])
elftextsh += 10;
break;
+ case 10:
+ break;
}
symsize = 0;
@@ -807,6 +811,10 @@ asmb(void)
symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
+ case 10:
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
}
/*
* the symbol information is stored as
@@ -829,7 +837,7 @@ asmb(void)
lputl(symsize);
lputl(lcsize);
cflush();
- if(!debug['s']) {
+ if(HEADTYPE != 10 && !debug['s']) {
elfsymo = symo+8+symsize+lcsize;
seek(cout, elfsymo, 0);
asmelfsym64();
@@ -907,14 +915,17 @@ asmb(void)
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
- switch(HEADTYPE) {
- case 7:
- elfinterp(sh, startva, linuxdynld);
- break;
- case 9:
- elfinterp(sh, startva, freebsddynld);
- break;
+ if(interpreter == nil) {
+ switch(HEADTYPE) {
+ case 7:
+ interpreter = linuxdynld;
+ break;
+ case 9:
+ interpreter = freebsddynld;
+ break;
+ }
}
+ elfinterp(sh, startva, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
@@ -1090,6 +1101,9 @@ asmb(void)
if(a+elfwriteinterp() > ELFRESERVE)
diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE);
break;
+ case 10:
+ asmbpe();
+ break;
}
cflush();
}
@@ -1143,6 +1157,7 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
case SDATA:
case SELFDATA:
case SMACHOGOT:
+ case SWINDOWS:
if(!s->reachable)
continue;
put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index 501317f36..97fa2cc5a 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -32,6 +32,8 @@ Options new in this version:
Write Apple Mach-O binaries (default when $GOOS is darwin)
-H7
Write Linux ELF binaries (default when $GOOS is linux)
+-I interpreter
+ Set the ELF dynamic linker to use.
-L dir1 -L dir2
Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_amd64.
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 1c52ea89d..7f22493e0 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -183,6 +183,7 @@ enum
SRODATA,
SDATA,
SMACHOGOT,
+ SWINDOWS,
SBSS,
SXREF,
@@ -196,7 +197,6 @@ enum
SSUB = 1<<8,
NHASH = 10007,
- NHUNK = 100000,
MINSIZ = 8,
STRINGSZ = 200,
MINLC = 1,
@@ -352,6 +352,7 @@ EXTERN int nerrors;
EXTERN char* noname;
EXTERN char* outfile;
EXTERN vlong pc;
+EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 96d78c3b9..f9e257842 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -36,6 +36,7 @@
#include "../ld/elf.h"
#include "../ld/macho.h"
#include "../ld/dwarf.h"
+#include "../ld/pe.h"
#include <ar.h>
char *noname = "<none>";
@@ -57,7 +58,7 @@ char* paramspace = "FP";
void
usage(void)
{
- fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n");
+ fprint(2, "usage: 6l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.6\n");
exits("usage");
}
@@ -95,6 +96,9 @@ main(int argc, char *argv[])
case 'H':
HEADTYPE = atolwhex(EARGF(usage()));
break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
case 'L':
Lflag(EARGF(usage()));
break;
@@ -133,6 +137,9 @@ main(int argc, char *argv[])
if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9;
else
+ if(strcmp(goos, "windows") == 0)
+ HEADTYPE = 10;
+ else
print("goos is not known: %s\n", goos);
}
@@ -200,6 +207,16 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
+ case 10: /* PE executable */
+ peinit();
+ HEADR = PEFILEHEADR;
+ if(INITTEXT == -1)
+ INITTEXT = PEBASE+PESECTHEADR;
+ if(INITDAT == -1)
+ INITDAT = 0;
+ if(INITRND == -1)
+ INITRND = PESECTALIGN;
+ break;
}
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%llux is ignored because of -R0x%ux\n",
@@ -245,6 +262,8 @@ main(int argc, char *argv[])
else
doprof2();
span();
+ if(HEADTYPE == 10)
+ dope();
addexport();
textaddress();
pclntab();
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index 5c4ed00a6..5eb221a35 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -277,6 +277,29 @@ patch(void)
vexit = s->value;
for(cursym = textp; cursym != nil; cursym = cursym->next)
for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 10) {
+ // Windows
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x58(GS), reg
+ // op n(reg), reg
+ // The purpose of this patch is to fix some accesses
+ // to extern register variables (TLS) on Windows, as
+ // a different method is used to access them.
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI
+ && p->from.offset != 0x58) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x58;
+ }
+ }
if(HEADTYPE == 7 || HEADTYPE == 9) {
// ELF uses FS instead of GS.
if(p->from.type == D_INDIR+D_GS)
@@ -411,6 +434,21 @@ dostkoff(void)
p->from.type = D_INDIR+D_GS;
p->from.offset = tlsoffset+0;
p->to.type = D_CX;
+ if(HEADTYPE == 10) { // Windows
+ // movq %gs:0x58, %rcx
+ // movq (%rcx), %rcx
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0x58;
+ p->to.type = D_CX;
+
+
+ p = appendp(p);
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ }
if(debug['K']) {
// 6l -K means check not only for stack
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index fe6b17280..3cb30f4c2 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -57,7 +57,6 @@ typedef struct Gen2 Gen2;
#define NSYMB 500
#define BUFSIZ 8192
#define HISTSZ 20
-#define NHUNK 10000
#define EOF (-1)
#define IGN (-2)
#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 875d434fa..9c326e8ef 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -174,7 +174,7 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
- case OCMPLX:
+ case OCOMPLEX:
fatal("unexpected complex");
return;
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 1c14dfe47..48edfdf3c 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -17,8 +17,6 @@ Typedef typedefs[] =
"int", TINT, TINT32,
"uint", TUINT, TUINT32,
"uintptr", TUINTPTR, TUINT32,
- "float", TFLOAT, TFLOAT32,
- "complex", TCOMPLEX, TCOMPLEX64,
0
};
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index e1dacf55a..1465d372c 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -1095,7 +1095,6 @@ allreg(uint32 b, Rgn *r)
case TFLOAT32:
case TFLOAT64:
- case TFLOAT:
break;
}
return 0;
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index 84976ba18..a85e3ffa7 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -16,6 +16,7 @@ OFILES=\
go.$O\
ldelf.$O\
ldmacho.$O\
+ ldpe.$O\
lib.$O\
list.$O\
macho.$O\
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index cdb5a33e6..6e83d8dea 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -520,7 +520,7 @@ adddynsym(Sym *s)
adduint8(d, 0); // section
adduint16(d, 0); // desc
adduint32(d, 0); // value
- } else {
+ } else if(HEADTYPE != 10) {
diag("adddynsym: unsupported binary format");
}
}
@@ -540,7 +540,7 @@ adddynlib(char *lib)
elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == 6) { // Mach-O
machoadddynlib(lib);
- } else {
+ } else if(HEADTYPE != 10) {
diag("adddynlib: unsupported binary format");
}
}
@@ -936,14 +936,17 @@ asmb(void)
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
- switch(HEADTYPE) {
- case 7:
- elfinterp(sh, startva, linuxdynld);
- break;
- case 9:
- elfinterp(sh, startva, freebsddynld);
- break;
+ if(interpreter == nil) {
+ switch(HEADTYPE) {
+ case 7:
+ interpreter = linuxdynld;
+ break;
+ case 9:
+ interpreter = freebsddynld;
+ break;
+ }
}
+ elfinterp(sh, startva, interpreter);
ph = newElfPhdr();
ph->type = PT_INTERP;
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
index 0bf6f151f..ef5ebc31d 100644
--- a/src/cmd/8l/doc.go
+++ b/src/cmd/8l/doc.go
@@ -29,6 +29,8 @@ Options new in this version:
Write Apple Mach-O binaries (default when $GOOS is darwin)
-H7
Write Linux ELF binaries (default when $GOOS is linux)
+-I interpreter
+ Set the ELF dynamic linker to use.
-L dir1 -L dir2
Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_386.
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index daede8879..e0746fc75 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -190,7 +190,6 @@ enum
SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
NHASH = 10007,
- NHUNK = 100000,
MINSIZ = 4,
STRINGSZ = 200,
MINLC = 1,
@@ -316,6 +315,7 @@ EXTERN int maxop;
EXTERN int nerrors;
EXTERN char* noname;
EXTERN int32 pc;
+EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 18b2112fe..fefb6d8b0 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -64,7 +64,7 @@ char *thestring = "386";
void
usage(void)
{
- fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n");
+ fprint(2, "usage: 8l [-options] [-E entry] [-H head] [-I interpreter] [-L dir] [-T text] [-R rnd] [-r path] [-o out] main.8\n");
exits("usage");
}
@@ -102,6 +102,9 @@ main(int argc, char *argv[])
case 'H':
HEADTYPE = atolwhex(EARGF(usage()));
break;
+ case 'I':
+ interpreter = EARGF(usage());
+ break;
case 'L':
Lflag(EARGF(usage()));
break;
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 6e387b0b5..878a73dac 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -38,8 +38,15 @@ static void xfol(Prog*, Prog**);
// see ../../pkg/runtime/proc.c:/StackGuard
enum
{
+#ifdef __WINDOWS__
+ // use larger stacks to compensate for larger stack guard,
+ // needed for exception handling.
+ StackSmall = 256,
+ StackBig = 8192,
+#else
StackSmall = 128,
StackBig = 4096,
+#endif
};
Prog*
@@ -510,7 +517,7 @@ dostkoff(void)
p->to.type = D_DX;
/* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
p->from.type = D_CONST;
- if(autoffset+160 > 4096)
+ if(autoffset+160+cursym->text->to.offset2 > 4096)
p->from.offset = (autoffset+160) & ~7LL;
p = appendp(p); // save arg size in AX
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
index 71f23383d..8327d9516 100644
--- a/src/cmd/cc/Makefile
+++ b/src/cmd/cc/Makefile
@@ -20,7 +20,7 @@ OFILES=\
mac.$O\
dcl.$O\
acid.$O\
- pickle.$O\
+ godefs.$O\
bits.$O\
com.$O\
scon.$O\
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 3649bf5f6..8e8f6af44 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -59,7 +59,6 @@ typedef struct Bits Bits;
typedef struct Dynimp Dynimp;
typedef struct Dynexp Dynexp;
-#define NHUNK 50000L
#define BUFSIZ 8192
#define NSYMB 500
#define NHASH 1024
@@ -745,9 +744,11 @@ void acidtype(Type*);
void acidvar(Sym*);
/*
- * pickle.c
+ * godefs.c
*/
-void pickletype(Type*);
+int Uconv(Fmt*);
+void godeftype(Type*);
+void godefvar(Sym*);
/*
* bits.c
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index f629925d1..d7604b649 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -130,6 +130,7 @@ loop:
if(debug['d'])
dbgdecl(s);
acidvar(s);
+ godefvar(s);
s->varlineno = lineno;
break;
}
@@ -587,7 +588,7 @@ sualign(Type *t)
t->width = w;
t->align = maxal;
acidtype(t);
- pickletype(t);
+ godeftype(t);
return;
case TUNION:
@@ -610,7 +611,7 @@ sualign(Type *t)
t->width = w;
t->align = maxal;
acidtype(t);
- pickletype(t);
+ godeftype(t);
return;
default:
@@ -1538,6 +1539,7 @@ doenum(Sym *s, Node *n)
if(debug['d'])
dbgdecl(s);
acidvar(s);
+ godefvar(s);
}
void
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 6eb5fb409..d78a72a2b 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -399,6 +399,7 @@ dpcheck(Node *n)
return;
i = l->param;
+ a = nil;
b = n->right;
a = Z;
while(i > 0) {
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
new file mode 100644
index 000000000..9503cb2f2
--- /dev/null
+++ b/src/cmd/cc/godefs.c
@@ -0,0 +1,387 @@
+// cmd/cc/godefs.cc
+//
+// derived from pickle.cc which itself was derived from acid.cc.
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009-2011 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "cc.h"
+
+static int upper;
+
+static char *kwd[] =
+{
+ "_bool",
+ "_break",
+ "_byte",
+ "_case",
+ "_chan",
+ "_complex128",
+ "_complex64",
+ "_const",
+ "_continue",
+ "_default",
+ "_defer",
+ "_else",
+ "_fallthrough",
+ "_false",
+ "_float32",
+ "_float64",
+ "_for",
+ "_func",
+ "_go",
+ "_goto",
+ "_if",
+ "_import",
+ "_int",
+ "_int16",
+ "_int32",
+ "_int64",
+ "_int8",
+ "_interface",
+ "_intptr",
+ "_map",
+ "_package",
+ "_panic",
+ "_range",
+ "_return",
+ "_select",
+ "_string",
+ "_struct",
+ "_switch",
+ "_true",
+ "_type",
+ "_uint",
+ "_uint16",
+ "_uint32",
+ "_uint64",
+ "_uint8",
+ "_uintptr",
+ "_var",
+};
+
+static char*
+pmap(char *s)
+{
+ int i, bot, top, mid;
+
+ bot = -1;
+ top = nelem(kwd);
+ while(top - bot > 1){
+ mid = (bot + top) / 2;
+ i = strcmp(kwd[mid]+1, s);
+ if(i == 0)
+ return kwd[mid];
+ if(i < 0)
+ bot = mid;
+ else
+ top = mid;
+ }
+
+ return s;
+}
+
+
+int
+Uconv(Fmt *fp)
+{
+ char str[STRINGSZ+1];
+ char *s, *n;
+ int i;
+
+ str[0] = 0;
+ s = va_arg(fp->args, char*);
+
+ // strip package name
+ n = strrchr(s, '.');
+ if(n != nil)
+ s = n + 1;
+
+ if(s && *s) {
+ if(upper)
+ str[0] = toupper(*s);
+ else
+ str[0] = tolower(*s);
+ for(i = 1; i < STRINGSZ && s[i] != 0; i++)
+ str[i] = tolower(s[i]);
+ str[i] = 0;
+ }
+
+ return fmtstrcpy(fp, pmap(str));
+}
+
+
+static Sym*
+findsue(Type *t)
+{
+ int h;
+ Sym *s;
+
+ if(t != T)
+ for(h=0; h<nelem(hash); h++)
+ for(s = hash[h]; s != S; s = s->link)
+ if(s->suetag && s->suetag->link == t)
+ return s;
+ return 0;
+}
+
+static void
+printtypename(Type *t)
+{
+ Sym *s;
+ Type *t1;
+ int w;
+ char *n;
+
+ for( ; t != nil; t = t->link) {
+ switch(t->etype) {
+ case TIND:
+ // Special handling of *void.
+ if(t->link != nil && t->link->etype==TVOID) {
+ Bprint(&outbuf, "unsafe.Pointer");
+ return;
+ }
+ // *func == func
+ if(t->link != nil && t->link->etype==TFUNC)
+ continue;
+ Bprint(&outbuf, "*");
+ continue;
+ case TARRAY:
+ w = t->width;
+ if(t->link && t->link->width)
+ w /= t->link->width;
+ Bprint(&outbuf, "[%d]", w);
+ continue;
+ }
+ break;
+ }
+
+ if(t == nil) {
+ Bprint(&outbuf, "bad // should not happen");
+ return;
+ }
+
+ switch(t->etype) {
+ case TINT:
+ Bprint(&outbuf, "int");
+ break;
+ case TUINT:
+ Bprint(&outbuf, "uint");
+ break;
+ case TCHAR:
+ Bprint(&outbuf, "int8");
+ break;
+ case TUCHAR:
+ Bprint(&outbuf, "uint8");
+ break;
+ case TSHORT:
+ Bprint(&outbuf, "int16");
+ break;
+ case TUSHORT:
+ Bprint(&outbuf, "uint16");
+ break;
+ case TLONG:
+ Bprint(&outbuf, "int32");
+ break;
+ case TULONG:
+ Bprint(&outbuf, "uint32");
+ break;
+ case TVLONG:
+ Bprint(&outbuf, "int64");
+ break;
+ case TUVLONG:
+ Bprint(&outbuf, "uint64");
+ break;
+ case TFLOAT:
+ Bprint(&outbuf, "float32");
+ break;
+ case TDOUBLE:
+ Bprint(&outbuf, "float64");
+ break;
+ case TUNION:
+ case TSTRUCT:
+ s = findsue(t->link);
+ n = "bad";
+ if(s != S)
+ n = s->name;
+ else if(t->tag)
+ n = t->tag->name;
+ if(strcmp(n, "String") == 0){
+ Bprint(&outbuf, "string");
+ } else if(strcmp(n, "Slice") == 0){
+ Bprint(&outbuf, "[]byte");
+ } else
+ Bprint(&outbuf, "%U", n);
+ break;
+ case TFUNC:
+ Bprint(&outbuf, "func(", t);
+ for(t1 = t->down; t1 != T; t1 = t1->down) {
+ if(t1->etype == TVOID)
+ break;
+ if(t1 != t->down)
+ Bprint(&outbuf, ", ");
+ printtypename(t1);
+ }
+ Bprint(&outbuf, ")");
+ if(t->link && t->link->etype != TVOID) {
+ Bprint(&outbuf, " ");
+ printtypename(t->link);
+ }
+ break;
+ case TDOT:
+ Bprint(&outbuf, "...interface{}");
+ break;
+ default:
+ Bprint(&outbuf, " weird<%T>", t);
+ }
+}
+
+static int
+dontrun(void)
+{
+ Io *i;
+ int n;
+
+ if(!debug['q'] && !debug['Q'])
+ return 1;
+ if(debug['q'] + debug['Q'] > 1) {
+ n = 0;
+ for(i=iostack; i; i=i->link)
+ n++;
+ if(n > 1)
+ return 1;
+ }
+
+ upper = debug['Q'];
+ return 0;
+}
+
+void
+godeftype(Type *t)
+{
+ Sym *s;
+ Type *l;
+ int gotone;
+
+ if(dontrun())
+ return;
+
+ switch(t->etype) {
+ case TUNION:
+ case TSTRUCT:
+ s = findsue(t->link);
+ if(s == S) {
+ Bprint(&outbuf, "/* can't find %T */\n\n", t);
+ return;
+ }
+
+ gotone = 0; // for unions, take first member of size equal to union
+ Bprint(&outbuf, "type %U struct {\n", s->name);
+ for(l = t->link; l != T; l = l->down) {
+ Bprint(&outbuf, "\t");
+ if(t->etype == TUNION) {
+ if(!gotone && l->width == t->width)
+ gotone = 1;
+ else
+ Bprint(&outbuf, "// (union)\t");
+ }
+ if(l->sym != nil) // not anonymous field
+ Bprint(&outbuf, "%U\t", l->sym->name);
+ printtypename(l);
+ Bprint(&outbuf, "\n");
+ }
+ Bprint(&outbuf, "}\n\n");
+ break;
+
+ default:
+ Bprint(&outbuf, "/* %T */\n\n", t);
+ break;
+ }
+}
+
+void
+godefvar(Sym *s)
+{
+ Type *t, *t1;
+ char n;
+
+ if(dontrun())
+ return;
+
+ t = s->type;
+ if(t == nil)
+ return;
+
+ switch(t->etype) {
+ case TENUM:
+ if(!typefd[t->etype])
+ Bprint(&outbuf, "const %U = %lld\n", s->name, s->vconst);
+ else
+ Bprint(&outbuf, "const %U = %f\n;", s->name, s->fconst);
+ break;
+
+ case TFUNC:
+ Bprint(&outbuf, "func %U(", s->name);
+ n = 'a';
+ for(t1 = t->down; t1 != T; t1 = t1->down) {
+ if(t1->etype == TVOID)
+ break;
+ if(t1 != t->down)
+ Bprint(&outbuf, ", ");
+ Bprint(&outbuf, "%c ", n++);
+ printtypename(t1);
+ }
+ Bprint(&outbuf, ")");
+ if(t->link && t->link->etype != TVOID) {
+ Bprint(&outbuf, " ");
+ printtypename(t->link);
+ }
+ Bprint(&outbuf, "\n");
+ break;
+
+ default:
+ switch(s->class) {
+ case CTYPEDEF:
+ if(!typesu[t->etype]) {
+ Bprint(&outbuf, "// type %U\t", s->name);
+ printtypename(t);
+ Bprint(&outbuf, "\n");
+ }
+ break;
+ case CSTATIC:
+ case CEXTERN:
+ case CGLOBL:
+ if(strchr(s->name, '$') != nil) // TODO(lvd)
+ break;
+ Bprint(&outbuf, "var %U\t", s->name);
+ printtypename(t);
+ Bprint(&outbuf, "\n");
+ break;
+ }
+ break;
+ }
+}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index 3b413c246..dba8ff634 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -59,15 +59,20 @@ pathchar(void)
* -d print declarations
* -D name define
* -F format specification check
+ * -G print pgen stuff
+ * -g print cgen trees
* -i print initialization
* -I path include
* -l generate little-endian code
* -L print every NAME symbol
* -M constant multiplication
* -m print add/sub/mul trees
- * -n print acid to file (%.c=%.acid) (with -a or -aa)
+ * -n print acid or godefs to file (%.c=%.acid) (with -a or -aa)
* -o file output file
* -p use standard cpp ANSI preprocessor (not on windows)
+ * -p something with peepholes
+ * -q print equivalent Go code for variables and types (lower-case identifiers)
+ * -Q print equivalent Go code for variables and types (upper-case identifiers)
* -r print registerization
* -s print structure offsets (with -a or -aa)
* -S print assembly
@@ -121,7 +126,7 @@ main(int argc, char *argv[])
p = ARGF();
if(p) {
if(ndef%8 == 0)
- defs = allocn(defs, ndef*sizeof(char *),
+ defs = allocn(defs, ndef*sizeof(char *),
8*sizeof(char *));
defs[ndef++] = p;
dodefine(p);
@@ -147,7 +152,7 @@ main(int argc, char *argv[])
* if we're writing acid to standard output, don't compile
* concurrently, to avoid interleaving output.
*/
- if(((!debug['a'] && !debug['Z']) || debug['n']) &&
+ if(((!debug['a'] && !debug['q'] && !debug['Q']) || debug['n']) &&
(p = getenv("NPROC")) != nil)
nproc = atol(p); /* */
c = 0;
@@ -220,8 +225,8 @@ compile(char *file, char **defs, int ndef)
p = utfrune(outfile, 0);
if(debug['a'] && debug['n'])
strcat(p, ".acid");
- else if(debug['Z'] && debug['n'])
- strcat(p, "_pickle.c");
+ else if((debug['q'] || debug['Q']) && debug['n'])
+ strcat(p, ".go");
else {
p[0] = '.';
p[1] = thechar;
@@ -246,7 +251,7 @@ compile(char *file, char **defs, int ndef)
* if we're writing acid to standard output, don't keep scratching
* outbuf.
*/
- if((debug['a'] || debug['Z']) && !debug['n']) {
+ if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) {
if (first) {
outfile = 0;
Binit(&outbuf, dup(1, -1), OWRITE);
@@ -325,7 +330,7 @@ compile(char *file, char **defs, int ndef)
newfile(file, -1);
}
yyparse();
- if(!debug['a'] && !debug['Z'])
+ if(!debug['a'] && !debug['q'] && !debug['Q'])
gclean();
return nerrors;
}
@@ -1309,6 +1314,7 @@ cinit(void)
fmtinstall('L', Lconv);
fmtinstall('Q', Qconv);
fmtinstall('|', VBconv);
+ fmtinstall('U', Uconv);
}
int
@@ -1554,7 +1560,7 @@ setinclude(char *p)
return;
if(ninclude%8 == 0)
- include = allocn(include, ninclude*sizeof(char *),
+ include = allocn(include, ninclude*sizeof(char *),
8*sizeof(char *));
include[ninclude++] = p;
}
@@ -1595,7 +1601,7 @@ ensuresymb(int32 n)
if(symb == nil) {
symb = alloc(NSYMB+1);
nsymb = NSYMB;
- }
+ }
if(n > nsymb) {
symb = allocn(symb, nsymb, n+1-nsymb);
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
index 0bccc1733..24f9bdc85 100644
--- a/src/cmd/cc/lexbody
+++ b/src/cmd/cc/lexbody
@@ -88,47 +88,32 @@ pragincomplete(void)
;
}
-void
-gethunk(void)
-{
- hunk = malloc(NHUNK);
- memset(hunk, 0, NHUNK);
- nhunk = NHUNK;
-}
-
void*
alloc(int32 n)
{
void *p;
- while((uintptr)hunk & MAXALIGN) {
- hunk++;
- nhunk--;
+ p = malloc(n);
+ if(p == nil) {
+ print("alloc out of mem\n");
+ exit(1);
}
- while(nhunk < n)
- gethunk();
- p = hunk;
- nhunk -= n;
- hunk += n;
+ memset(p, 0, n);
return p;
}
void*
-allocn(void *p, int32 on, int32 n)
+allocn(void *p, int32 n, int32 d)
{
- void *q;
-
- q = (uchar*)p + on;
- if(q != hunk || nhunk < n) {
- while(nhunk < on+n)
- gethunk();
- memmove(hunk, p, on);
- p = hunk;
- hunk += on;
- nhunk -= on;
+ if(p == nil)
+ return alloc(n+d);
+ p = realloc(p, n+d);
+ if(p == nil) {
+ print("allocn out of mem\n");
+ exit(1);
}
- hunk += n;
- nhunk -= n;
+ if(d > 0)
+ memset((char*)p+n, 0, d);
return p;
}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index a9d7f1ef4..5d17cafc9 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -586,8 +586,7 @@ bcomplex(Node *n, Node *c)
*b->right = *nodconst(0);
b->right->type = n->type;
b->type = types[TLONG];
- cgen(b, Z);
- return 0;
+ n = b;
}
bool64(n);
boolgen(n, 1, Z);
diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c
deleted file mode 100644
index 82cf5eb05..000000000
--- a/src/cmd/cc/pickle.c
+++ /dev/null
@@ -1,298 +0,0 @@
-// Inferno utils/cc/pickle.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/pickle.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-// Portions Copyright © 1997-1999 Vita Nuova Limited
-// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-// Portions Copyright © 2004,2006 Bruce Ellis
-// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-// Portions Copyright © 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#include "cc.h"
-
-static char *kwd[] =
-{
- "$adt", "$aggr", "$append", "$complex", "$defn",
- "$delete", "$do", "$else", "$eval", "$head", "$if",
- "$local", "$loop", "$return", "$tail", "$then",
- "$union", "$whatis", "$while",
-};
-static char picklestr[] = "\tbp = pickle(bp, ep, un, ";
-
-static char*
-pmap(char *s)
-{
- int i, bot, top, new;
-
- bot = 0;
- top = bot + nelem(kwd) - 1;
- while(bot <= top){
- new = bot + (top - bot)/2;
- i = strcmp(kwd[new]+1, s);
- if(i == 0)
- return kwd[new];
-
- if(i < 0)
- bot = new + 1;
- else
- top = new - 1;
- }
- return s;
-}
-
-Sym*
-picklesue(Type *t)
-{
- int h;
- Sym *s;
-
- if(t != T)
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->suetag && s->suetag->link == t)
- return s;
- return 0;
-}
-
-Sym*
-picklefun(Type *t)
-{
- int h;
- Sym *s;
-
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->type == t)
- return s;
- return 0;
-}
-
-char picklechar[NTYPE];
-Init picklecinit[] =
-{
- TCHAR, 'C', 0,
- TUCHAR, 'b', 0,
- TSHORT, 'd', 0,
- TUSHORT, 'u', 0,
- TLONG, 'D', 0,
- TULONG, 'U', 0,
- TVLONG, 'V', 0,
- TUVLONG, 'W', 0,
- TFLOAT, 'f', 0,
- TDOUBLE, 'F', 0,
- TARRAY, 'a', 0,
- TIND, 'X', 0,
- -1, 0, 0,
-};
-
-static void
-pickleinit(void)
-{
- Init *p;
-
- for(p=picklecinit; p->code >= 0; p++)
- picklechar[p->code] = p->value;
-
- picklechar[TINT] = picklechar[TLONG];
- picklechar[TUINT] = picklechar[TULONG];
- if(types[TINT]->width != types[TLONG]->width) {
- picklechar[TINT] = picklechar[TSHORT];
- picklechar[TUINT] = picklechar[TUSHORT];
- if(types[TINT]->width != types[TSHORT]->width)
- warn(Z, "picklemember int not long or short");
- }
-
-}
-
-void
-picklemember(Type *t, int32 off)
-{
- Sym *s, *s1;
- static int picklecharinit = 0;
-
- if(picklecharinit == 0) {
- pickleinit();
- picklecharinit = 1;
- }
- s = t->sym;
- switch(t->etype) {
- default:
- Bprint(&outbuf, " T%d\n", t->etype);
- break;
-
- case TIND:
- if(s == S)
- Bprint(&outbuf,
- "%s\"p\", (char*)addr+%d+_i*%d);\n",
- picklestr, t->offset+off, t->width);
- else
- Bprint(&outbuf,
- "%s\"p\", &addr->%s);\n",
- picklestr, pmap(s->name));
- break;
-
- case TINT:
- case TUINT:
- case TCHAR:
- case TUCHAR:
- case TSHORT:
- case TUSHORT:
- case TLONG:
- case TULONG:
- case TVLONG:
- case TUVLONG:
- case TFLOAT:
- case TDOUBLE:
- if(s == S)
- Bprint(&outbuf, "%s\"%c\", (char*)addr+%d+_i*%d);\n",
- picklestr, picklechar[t->etype], t->offset+off, t->width);
- else
- Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
- picklestr, picklechar[t->etype], pmap(s->name));
- break;
- case TARRAY:
- Bprint(&outbuf, "\tfor(_i = 0; _i < %d; _i++) {\n\t",
- t->width/t->link->width);
- picklemember(t->link, t->offset+off);
- Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
- break;
-
- case TSTRUCT:
- case TUNION:
- s1 = picklesue(t->link);
- if(s1 == S)
- break;
- if(s == S) {
- Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%d+_i*%d));\n",
- pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
- } else {
- Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
- pmap(s1->name), pmap(s->name));
- }
- break;
- }
-}
-
-void
-pickletype(Type *t)
-{
- Sym *s;
- Type *l;
- Io *i;
- int n;
- char *an;
-
- if(!debug['P'])
- return;
- if(debug['P'] > 1) {
- n = 0;
- for(i=iostack; i; i=i->link)
- n++;
- if(n > 1)
- return;
- }
- s = picklesue(t->link);
- if(s == S)
- return;
- switch(t->etype) {
- default:
- Bprint(&outbuf, "T%d\n", t->etype);
- return;
-
- case TUNION:
- case TSTRUCT:
- if(debug['s'])
- goto asmstr;
- an = pmap(s->name);
-
- Bprint(&outbuf, "char *\npickle_%s(char *bp, char *ep, int un, %s *addr)\n{\n\tint _i = 0;\n\n\tUSED(_i);\n", an, an);
- for(l = t->link; l != T; l = l->down)
- picklemember(l, 0);
- Bprint(&outbuf, "\treturn bp;\n}\n\n");
- break;
- asmstr:
- if(s == S)
- break;
- for(l = t->link; l != T; l = l->down)
- if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%d\n",
- s->name,
- l->sym->name,
- l->offset);
- break;
- }
-}
-
-void
-picklevar(Sym *s)
-{
- int n;
- Io *i;
- Type *t;
- Sym *s1, *s2;
-
- if(!debug['P'] || debug['s'])
- return;
- if(debug['P'] > 1) {
- n = 0;
- for(i=iostack; i; i=i->link)
- n++;
- if(n > 1)
- return;
- }
- t = s->type;
- while(t && t->etype == TIND)
- t = t->link;
- if(t == T)
- return;
- if(t->etype == TENUM) {
- Bprint(&outbuf, "%s = ", pmap(s->name));
- if(!typefd[t->etype])
- Bprint(&outbuf, "%lld;\n", s->vconst);
- else
- Bprint(&outbuf, "%f\n;", s->fconst);
- return;
- }
- if(!typesu[t->etype])
- return;
- s1 = picklesue(t->link);
- if(s1 == S)
- return;
- switch(s->class) {
- case CAUTO:
- case CPARAM:
- s2 = picklefun(thisfn);
- if(s2)
- Bprint(&outbuf, "complex %s %s:%s;\n",
- pmap(s1->name), pmap(s2->name), pmap(s->name));
- break;
-
- case CSTATIC:
- case CEXTERN:
- case CGLOBL:
- case CLOCAL:
- Bprint(&outbuf, "complex %s %s;\n",
- pmap(s1->name), pmap(s->name));
- break;
- }
-}
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 8689ac3da..2eae22aed 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -35,6 +35,10 @@ func parse(name string, flags uint) *ast.File {
return ast1
}
+func sourceLine(n ast.Node) int {
+ return fset.Position(n.Pos()).Line
+}
+
// ReadGo populates f with information learned from reading the
// Go source file with the given file name. It gathers the C preamble
// attached to the import "C" comment, a list of references to C.xxx,
@@ -69,10 +73,13 @@ func (f *File) ReadGo(name string) {
if s.Name != nil {
error(s.Path.Pos(), `cannot rename import "C"`)
}
- if s.Doc != nil {
- f.Preamble += doc.CommentText(s.Doc) + "\n"
- } else if len(d.Specs) == 1 && d.Doc != nil {
- f.Preamble += doc.CommentText(d.Doc) + "\n"
+ cg := s.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
+ }
+ if cg != nil {
+ f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name)
+ f.Preamble += doc.CommentText(cg) + "\n"
}
}
}
@@ -298,6 +305,9 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
f.walk(n.Stmt, "stmt", visit)
case *ast.ExprStmt:
f.walk(&n.X, "expr", visit)
+ case *ast.SendStmt:
+ f.walk(&n.Chan, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
case *ast.IncDecStmt:
f.walk(&n.X, "expr", visit)
case *ast.AssignStmt:
@@ -336,8 +346,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
f.walk(n.Assign, "stmt", visit)
f.walk(n.Body, "stmt", visit)
case *ast.CommClause:
- f.walk(n.Lhs, "expr", visit)
- f.walk(n.Rhs, "expr", visit)
+ f.walk(n.Comm, "stmt", visit)
f.walk(n.Body, "stmt", visit)
case *ast.SelectStmt:
f.walk(n.Body, "stmt", visit)
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 0f9204d7f..c4868345c 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -23,6 +23,15 @@ the package. For example:
// #include <errno.h>
import "C"
+CFLAGS and LDFLAGS may be defined with pseudo #cgo directives
+within these comments to tweak the behavior of gcc. Values defined
+in multiple directives are concatenated together. For example:
+
+ // #cgo CFLAGS: -DPNG_DEBUG=1
+ // #cgo LDFLAGS: -lpng
+ // #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.
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index be3b8fe64..cadc6fae9 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -21,19 +21,22 @@ import (
"os"
"strconv"
"strings"
+ "unicode"
)
var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
var nameToC = map[string]string{
- "schar": "signed char",
- "uchar": "unsigned char",
- "ushort": "unsigned short",
- "uint": "unsigned int",
- "ulong": "unsigned long",
- "longlong": "long long",
- "ulonglong": "unsigned long long",
+ "schar": "signed char",
+ "uchar": "unsigned char",
+ "ushort": "unsigned short",
+ "uint": "unsigned int",
+ "ulong": "unsigned long",
+ "longlong": "long long",
+ "ulonglong": "unsigned long long",
+ "complexfloat": "float complex",
+ "complexdouble": "double complex",
}
// cname returns the C name to use for C.s.
@@ -57,6 +60,107 @@ func cname(s string) string {
return s
}
+// ParseFlags extracts #cgo CFLAGS and LDFLAGS options from the file
+// preamble. Multiple occurrences are concatenated with a separating space,
+// even across files.
+func (p *Package) ParseFlags(f *File, srcfile string) {
+ linesIn := strings.Split(f.Preamble, "\n", -1)
+ linesOut := make([]string, 0, len(linesIn))
+ for _, line := range linesIn {
+ l := strings.TrimSpace(line)
+ if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {
+ linesOut = append(linesOut, line)
+ continue
+ }
+
+ l = strings.TrimSpace(l[4:])
+ fields := strings.Split(l, ":", 2)
+ if len(fields) != 2 {
+ fatal("%s: bad #cgo line: %s", srcfile, line)
+ }
+
+ k := fields[0]
+ v := strings.TrimSpace(fields[1])
+ if k != "CFLAGS" && k != "LDFLAGS" {
+ fatal("%s: unsupported #cgo option %s", srcfile, k)
+ }
+ args, err := splitQuoted(v)
+ if err != nil {
+ fatal("%s: bad #cgo option %s: %s", srcfile, k, err.String())
+ }
+ if oldv, ok := p.CgoFlags[k]; ok {
+ p.CgoFlags[k] = oldv + " " + v
+ } else {
+ p.CgoFlags[k] = v
+ }
+ if k == "CFLAGS" {
+ p.GccOptions = append(p.GccOptions, args...)
+ }
+ }
+ f.Preamble = strings.Join(linesOut, "\n")
+}
+
+// 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.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// `a b:"c d" 'e''f' "g\""`
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+//
+func splitQuoted(s string) (r []string, err os.Error) {
+ var args []string
+ arg := make([]int, len(s))
+ escaped := false
+ quoted := false
+ quote := 0
+ i := 0
+ for _, rune := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case rune == '\\':
+ escaped = true
+ continue
+ case quote != 0:
+ if rune == quote {
+ quote = 0
+ continue
+ }
+ case rune == '"' || rune == '\'':
+ quoted = true
+ quote = rune
+ continue
+ case unicode.IsSpace(rune):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
+ }
+ continue
+ }
+ arg[i] = rune
+ i++
+ }
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = os.ErrorString("unclosed quote")
+ } else if escaped {
+ err = os.ErrorString("unfinished escaping")
+ }
+ return args, err
+}
+
// 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.
@@ -205,9 +309,7 @@ func (p *Package) guessKinds(f *File) []*Name {
for _, line := range strings.Split(stderr, "\n", -1) {
if len(line) < 9 || line[0:9] != "cgo-test:" {
- if len(line) > 8 && line[0:8] == "<stdin>:" {
- fatal("gcc produced unexpected output:\n%s\non input:\n%s", line, b.Bytes())
- }
+ // the user will see any compiler errors when the code is compiled later.
continue
}
line = line[9:]
@@ -568,10 +670,6 @@ func runGcc(stdin []byte, args []string) (string, string) {
os.Stderr.Write(stderr)
}
if !ok {
- fmt.Fprint(os.Stderr, "Error running gcc:\n")
- fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
- os.Stderr.Write(stdin)
- fmt.Fprint(os.Stderr, "EOF\n")
os.Stderr.Write(stderr)
os.Exit(2)
}
@@ -591,6 +689,7 @@ type typeConv struct {
int8, int16, int32, int64 ast.Expr
uint8, uint16, uint32, uint64, uintptr ast.Expr
float32, float64 ast.Expr
+ complex64, complex128 ast.Expr
void ast.Expr
unsafePointer ast.Expr
string ast.Expr
@@ -617,6 +716,8 @@ func (c *typeConv) Init(ptrSize int64) {
c.uintptr = c.Ident("uintptr")
c.float32 = c.Ident("float32")
c.float64 = c.Ident("float64")
+ c.complex64 = c.Ident("complex64")
+ c.complex128 = c.Ident("complex128")
c.unsafePointer = c.Ident("unsafe.Pointer")
c.void = c.Ident("void")
c.string = c.Ident("string")
@@ -648,6 +749,8 @@ var dwarfToName = map[string]string{
"long long int": "longlong",
"long long unsigned int": "ulonglong",
"signed char": "schar",
+ "float complex": "complexfloat",
+ "double complex": "complexdouble",
}
// Type returns a *Type with the same memory layout as
@@ -749,6 +852,19 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Align = c.ptrSize
}
+ case *dwarf.ComplexType:
+ switch t.Size {
+ default:
+ fatal("unexpected: %d-byte complex type - %s", t.Size, dtype)
+ case 8:
+ t.Go = c.complex64
+ case 16:
+ t.Go = c.complex128
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
case *dwarf.FuncType:
// No attempt at translation: would enable calls
// directly between worlds, but we need to moderate those.
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 942bda5f4..b15d34527 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -20,6 +20,7 @@ import (
"os"
"reflect"
"strings"
+ "runtime"
)
// A Package collects information about the package we're going to write.
@@ -28,6 +29,7 @@ type Package struct {
PackagePath string
PtrSize int64
GccOptions []string
+ CgoFlags map[string]string // #cgo flags (CFLAGS, LDFLAGS)
Written map[string]bool
Name map[string]*Name // accumulated Name from Files
Typedef map[string]ast.Expr // accumulated Typedef from Files
@@ -97,7 +99,8 @@ type FuncType struct {
}
func usage() {
- fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n")
+ fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
+ flag.PrintDefaults()
os.Exit(2)
}
@@ -127,6 +130,13 @@ func main() {
// specialized knowledge gcc has about where to look for imported
// symbols and which ones to use.
syms, imports := dynimport(*dynobj)
+ if runtime.GOOS == "windows" {
+ for _, sym := range syms {
+ ss := strings.Split(sym, ":", -1)
+ fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
+ }
+ return
+ }
for _, sym := range syms {
fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "")
}
@@ -152,7 +162,12 @@ func main() {
if i == len(args) {
usage()
}
- gccOptions, goFiles := args[0:i], args[i:]
+
+ // Copy it to a new slice so it can grow.
+ gccOptions := make([]string, i)
+ copy(gccOptions, args[0:i])
+
+ goFiles := args[i:]
arch := os.Getenv("GOARCH")
if arch == "" {
@@ -171,6 +186,7 @@ func main() {
p := &Package{
PtrSize: ptrSize,
GccOptions: gccOptions,
+ CgoFlags: make(map[string]string),
Written: make(map[string]bool),
}
@@ -190,11 +206,17 @@ func main() {
}
cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
- for _, input := range goFiles {
+ fs := make([]*File, len(goFiles))
+ for i, input := range goFiles {
+ // Parse flags for all files before translating due to CFLAGS.
f := new(File)
- // Reset f.Preamble so that we don't end up with conflicting headers / defines
- f.Preamble = ""
f.ReadGo(input)
+ p.ParseFlags(f, input)
+ fs[i] = f
+ }
+
+ for i, input := range goFiles {
+ f := fs[i]
p.Translate(f)
for _, cref := range f.Ref {
switch cref.Context {
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index c3f9ae60b..ede8f57d8 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -8,6 +8,7 @@ import (
"bytes"
"debug/elf"
"debug/macho"
+ "debug/pe"
"fmt"
"go/ast"
"go/printer"
@@ -32,9 +33,17 @@ func (p *Package) writeDefs() {
fc := creat("_cgo_defun.c")
fm := creat("_cgo_main.c")
+ fflg := creat("_cgo_flags")
+ for k, v := range p.CgoFlags {
+ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
+ }
+ fflg.Close()
+
// Write C main file for using gcc to resolve imports.
fmt.Fprintf(fm, "int main() { return 0; }\n")
- fmt.Fprintf(fm, "int crosscall2;\n\n")
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+ fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
+ fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
@@ -101,12 +110,14 @@ func dynimport(obj string) (syms, imports []string) {
ImportedSymbols() ([]string, os.Error)
}
var isMacho bool
- var err1, err2 os.Error
+ var err1, err2, err3 os.Error
if f, err1 = elf.Open(obj); err1 != nil {
- if f, err2 = macho.Open(obj); err2 != nil {
- fatal("cannot parse %s as ELF (%v) or Mach-O (%v)", obj, err1, err2)
+ if f, err2 = pe.Open(obj); err2 != nil {
+ if f, err3 = macho.Open(obj); err3 != nil {
+ fatal("cannot parse %s as ELF (%v) or PE (%v) or Mach-O (%v)", obj, err1, err2, err3)
+ }
+ isMacho = true
}
- isMacho = true
}
var err os.Error
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
index 10cb5b387..5eb398735 100644
--- a/src/cmd/ebnflint/ebnflint.go
+++ b/src/cmd/ebnflint/ebnflint.go
@@ -88,6 +88,7 @@ func main() {
src, err := ioutil.ReadFile(filename)
if err != nil {
scanner.PrintError(os.Stderr, err)
+ os.Exit(1)
}
if path.Ext(filename) == ".html" {
@@ -97,9 +98,11 @@ func main() {
grammar, err := ebnf.Parse(fset, filename, src)
if err != nil {
scanner.PrintError(os.Stderr, err)
+ os.Exit(1)
}
if err = ebnf.Verify(fset, grammar, *start); err != nil {
scanner.PrintError(os.Stderr, err)
+ os.Exit(1)
}
}
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index a3785e871..ed20e7e8b 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -412,11 +412,9 @@ typeinit(void)
isfloat[TFLOAT32] = 1;
isfloat[TFLOAT64] = 1;
- isfloat[TFLOAT] = 1;
iscomplex[TCOMPLEX64] = 1;
iscomplex[TCOMPLEX128] = 1;
- iscomplex[TCOMPLEX] = 1;
isptr[TPTR32] = 1;
isptr[TPTR64] = 1;
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 380abc642..48f45293f 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -66,16 +66,18 @@ char *runtimeimport =
"func \"\".mapiter2 (hiter *any) (key any, val any)\n"
"func \"\".makechan (elem *uint8, hint int64) chan any\n"
"func \"\".chanrecv1 (hchan <-chan any) any\n"
- "func \"\".chanrecv2 (hchan <-chan any) (elem any, pres bool)\n"
+ "func \"\".chanrecv3 (hchan <-chan any) (elem any, closed bool)\n"
"func \"\".chansend1 (hchan chan<- any, elem any)\n"
- "func \"\".chansend2 (hchan chan<- any, elem any) bool\n"
"func \"\".closechan (hchan any)\n"
"func \"\".closedchan (hchan any) bool\n"
+ "func \"\".selectnbsend (hchan chan<- any, elem any) bool\n"
+ "func \"\".selectnbrecv (elem *any, hchan <-chan any) bool\n"
"func \"\".newselect (size int) *uint8\n"
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) bool\n"
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) bool\n"
"func \"\".selectdefault (sel *uint8) bool\n"
"func \"\".selectgo (sel *uint8)\n"
+ "func \"\".block ()\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
"func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
"func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index 72e67a634..0ee693c02 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -980,10 +980,10 @@ defaultlit(Node **np, Type *t)
n->type = types[TINT];
goto num;
case CTFLT:
- n->type = types[TFLOAT];
+ n->type = types[TFLOAT64];
goto num;
case CTCPLX:
- n->type = types[TCOMPLEX];
+ n->type = types[TCOMPLEX128];
goto num;
num:
if(t != T) {
@@ -1034,13 +1034,13 @@ defaultlit2(Node **lp, Node **rp, int force)
if(!force)
return;
if(isconst(l, CTCPLX) || isconst(r, CTCPLX)) {
- convlit(lp, types[TCOMPLEX]);
- convlit(rp, types[TCOMPLEX]);
+ convlit(lp, types[TCOMPLEX128]);
+ convlit(rp, types[TCOMPLEX128]);
return;
}
if(isconst(l, CTFLT) || isconst(r, CTFLT)) {
- convlit(lp, types[TFLOAT]);
- convlit(rp, types[TFLOAT]);
+ convlit(lp, types[TFLOAT64]);
+ convlit(rp, types[TFLOAT64]);
return;
}
convlit(lp, types[TINT]);
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
index e25f3cabb..3ec9fe5a2 100644
--- a/src/cmd/gc/cplx.c
+++ b/src/cmd/gc/cplx.c
@@ -84,7 +84,7 @@ maybe:
case OSUB:
case OMUL:
case OMINUS:
- case OCMPLX:
+ case OCOMPLEX:
case OREAL:
case OIMAG:
goto yes;
@@ -120,7 +120,7 @@ complexgen(Node *n, Node *res)
// pick off float/complex opcodes
switch(n->op) {
- case OCMPLX:
+ case OCOMPLEX:
if(res->addable) {
subnode(&n1, &n2, res);
tempname(&tmp, n1.type);
@@ -195,7 +195,7 @@ complexgen(Node *n, Node *res)
case OSUB:
case OMUL:
case OMINUS:
- case OCMPLX:
+ case OCOMPLEX:
case OREAL:
case OIMAG:
break;
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 73ea5b976..bf84c12a1 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -356,7 +356,7 @@ enum
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
- OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECV, OAS2MAPR, OAS2DOTTYPE, OASOP,
+ OAS, OAS2, OAS2MAPW, OAS2FUNC, OAS2RECVCLOSED, OAS2MAPR, OAS2DOTTYPE, OASOP,
OBAD,
OCALL, OCALLFUNC, OCALLMETH, OCALLINTER,
OCAP,
@@ -383,14 +383,14 @@ enum
ONOT, OCOM, OPLUS, OMINUS,
OOROR,
OPANIC, OPRINT, OPRINTN,
- OSEND, OSENDNB,
+ OSEND,
OSLICE, OSLICEARR, OSLICESTR,
ORECOVER,
ORECV,
ORUNESTR,
OSELRECV,
OIOTA,
- OREAL, OIMAG, OCMPLX,
+ OREAL, OIMAG, OCOMPLEX,
// stmts
OBLOCK,
@@ -440,11 +440,9 @@ enum
TCOMPLEX64, // 12
TCOMPLEX128,
- TCOMPLEX,
TFLOAT32, // 15
TFLOAT64,
- TFLOAT,
TBOOL, // 18
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 917265758..994840ee8 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -93,9 +93,10 @@ static void fixlbrace(int);
%type <type> hidden_type_func
%type <type> hidden_type_recv_chan hidden_type_non_recv_chan
+%left LCOMM /* outside the usual hierarchy; here for good error messages */
+
%left LOROR
%left LANDAND
-%left LCOMM
%left LEQ LNE LLE LGE LLT LGT
%left '+' '-' '|' '^'
%left '*' '/' '%' '&' LLSH LRSH LANDNOT
@@ -421,11 +422,18 @@ simple_stmt:
| expr_list LCOLAS expr_list
{
if($3->n->op == OTYPESW) {
+ Node *n;
+
+ n = N;
if($3->next != nil)
yyerror("expr.(type) must be alone in list");
- else if($1->next != nil)
+ if($1->next != nil)
yyerror("argument count mismatch: %d = %d", count($1), 1);
- $$ = nod(OTYPESW, $1->n, $3->n->right);
+ else if($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME)
+ yyerror("invalid variable name %#N in type switch", $1->n);
+ else
+ n = $1->n;
+ $$ = nod(OTYPESW, n, $3->n->right);
break;
}
$$ = colas($1, $3);
@@ -764,6 +772,7 @@ expr:
{
$$ = nod(ORSH, $1, $3);
}
+ /* not an expression anymore, but left in so we can give a good error */
| expr LCOMM expr
{
$$ = nod(OSEND, $1, $3);
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 0f1acd2fc..45b1257fa 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -1531,7 +1531,7 @@ static struct
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
- "cmplx", LNAME, Txxx, OCMPLX,
+ "complex", LNAME, Txxx, OCOMPLEX,
"copy", LNAME, Txxx, OCOPY,
"imag", LNAME, Txxx, OIMAG,
"len", LNAME, Txxx, OLEN,
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index 6bb1f026b..695a5a397 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -48,6 +48,7 @@ exprfmt(Fmt *f, Node *n, int prec)
case ODOTMETH:
case ODOTTYPE:
case ODOTTYPE2:
+ case OXDOT:
case OARRAYBYTESTR:
case OCAP:
case OCLOSE:
@@ -365,8 +366,8 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, ")");
break;
- case OCMPLX:
- fmtprint(f, "cmplx(");
+ case OCOMPLEX:
+ fmtprint(f, "complex(");
exprfmt(f, n->left, 0);
fmtprint(f, ", ");
exprfmt(f, n->right, 0);
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index dca3a5454..4ee8f39a7 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -93,6 +93,7 @@ walkrange(Node *n)
Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2
Node *ha, *hit; // hidden aggregate, iterator
Node *hn, *hp; // hidden len, pointer
+ Node *hb; // hidden bool
Node *a, *v1, *v2; // not hidden aggregate, val 1, 2
Node *fn, *tmp;
NodeList *body, *init;
@@ -199,9 +200,15 @@ walkrange(Node *n)
case TCHAN:
hv1 = nod(OXXX, N, n);
tempname(hv1, t->type);
-
- n->ntest = nod(ONOT, nod(OCLOSED, ha, N), N);
- n->ntest->ninit = list1(nod(OAS, hv1, nod(ORECV, ha, N)));
+ hb = nod(OXXX, N, N);
+ tempname(hb, types[TBOOL]);
+
+ n->ntest = nod(ONOT, hb, N);
+ a = nod(OAS2RECVCLOSED, N, N);
+ a->typecheck = 1;
+ a->list = list(list1(hv1), hb);
+ a->rlist = list1(nod(ORECV, ha, N));
+ n->ntest->ninit = list1(a);
body = list1(nod(OAS, v1, hv1));
break;
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index b31eb5154..36c245d47 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -419,10 +419,8 @@ enum {
KindUint32,
KindUint64,
KindUintptr,
- KindFloat,
KindFloat32,
KindFloat64,
- KindComplex,
KindComplex64,
KindComplex128,
KindArray,
@@ -453,7 +451,6 @@ kinds[] =
[TINT64] = KindInt64,
[TUINT64] = KindUint64,
[TUINTPTR] = KindUintptr,
- [TFLOAT] = KindFloat,
[TFLOAT32] = KindFloat32,
[TFLOAT64] = KindFloat64,
[TBOOL] = KindBool,
@@ -466,7 +463,6 @@ kinds[] =
[TMAP] = KindMap,
[TARRAY] = KindArray,
[TFUNC] = KindFunc,
- [TCOMPLEX] = KindComplex,
[TCOMPLEX64] = KindComplex64,
[TCOMPLEX128] = KindComplex128,
};
@@ -485,10 +481,8 @@ structnames[] =
[TINT64] = "*runtime.IntType",
[TUINT64] = "*runtime.UintType",
[TUINTPTR] = "*runtime.UintType",
- [TCOMPLEX] = "*runtime.ComplexType",
[TCOMPLEX64] = "*runtime.ComplexType",
[TCOMPLEX128] = "*runtime.ComplexType",
- [TFLOAT] = "*runtime.FloatType",
[TFLOAT32] = "*runtime.FloatType",
[TFLOAT64] = "*runtime.FloatType",
[TBOOL] = "*runtime.BoolType",
@@ -542,7 +536,6 @@ haspointers(Type *t)
case TINT64:
case TUINT64:
case TUINTPTR:
- case TFLOAT:
case TFLOAT32:
case TFLOAT64:
case TBOOL:
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 174bc050e..bf7d045c0 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -92,17 +92,20 @@ func mapiter2(hiter *any) (key any, val any)
// *byte is really *runtime.Type
func makechan(elem *byte, hint int64) (hchan chan any)
func chanrecv1(hchan <-chan any) (elem any)
-func chanrecv2(hchan <-chan any) (elem any, pres bool)
+func chanrecv3(hchan <-chan any) (elem any, closed bool)
func chansend1(hchan chan<- any, elem any)
-func chansend2(hchan chan<- any, elem any) (pres bool)
func closechan(hchan any)
func closedchan(hchan any) bool
+func selectnbsend(hchan chan<- any, elem any) bool
+func selectnbrecv(elem *any, hchan <-chan any) bool
+
func newselect(size int) (sel *byte)
func selectsend(sel *byte, hchan chan<- any, elem any) (selected bool)
func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
+func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 1a3771311..5686e9599 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -45,27 +45,23 @@ typecheckselect(Node *sel)
break;
case OAS:
- // convert x = <-c into OSELRECV(x, c)
- // assignment might have introduced a
- // conversion. throw it away.
- // it will come back when the select code
- // gets generated, because it always assigns
- // through a temporary.
+ // convert x = <-c into OSELRECV(x, <-c).
+ // remove implicit conversions; the eventual assignment
+ // will reintroduce them.
if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
n->right = n->right->left;
+
if(n->right->op != ORECV) {
yyerror("select assignment must have receive on right hand side");
break;
}
n->op = OSELRECV;
- n->right = n->right->left;
break;
case ORECV:
- // convert <-c into OSELRECV(N, c)
- n->op = OSELRECV;
- n->right = n->left;
- n->left = N;
+ // convert <-c into OSELRECV(N, <-c)
+ n = nod(OSELRECV, N, n);
+ ncase->left = n;
break;
case OSEND:
@@ -81,11 +77,149 @@ typecheckselect(Node *sel)
void
walkselect(Node *sel)
{
- int lno;
- Node *n, *ncase, *r, *a, *tmp, *var;
+ int lno, i;
+ Node *n, *r, *a, *tmp, *var, *cas, *dflt, *ch;
NodeList *l, *init;
-
+
+ if(sel->list == nil && sel->xoffset != 0)
+ fatal("double walkselect"); // already rewrote
+
lno = setlineno(sel);
+ i = count(sel->list);
+
+ // optimization: zero-case select
+ if(i == 0) {
+ sel->nbody = list1(mkcall("block", nil, nil));
+ goto out;
+ }
+
+ // optimization: one-case select: single op.
+ if(i == 1) {
+ cas = sel->list->n;
+ l = cas->ninit;
+ if(cas->left != N) { // not default:
+ n = cas->left;
+ l = concat(l, n->ninit);
+ n->ninit = nil;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ ch = cheapexpr(n->left, &l);
+ n->left = ch;
+ break;
+
+ case OSELRECV:
+ r = n->right;
+ ch = cheapexpr(r->left, &l);
+ r->left = ch;
+
+ if(n->left == N)
+ n = r;
+ else {
+ n = nod(OAS, n->left, r);
+ typecheck(&n, Etop);
+ }
+ break;
+ }
+
+ // if ch == nil { block() }; n;
+ a = nod(OIF, N, N);
+ a->ntest = nod(OEQ, ch, nodnil());
+ a->nbody = list1(mkcall("block", nil, &l));
+ typecheck(&a, Etop);
+ l = list(l, a);
+ l = list(l, n);
+ }
+ l = concat(l, cas->nbody);
+ sel->nbody = l;
+ goto out;
+ }
+
+ // introduce temporary variables for OSELRECV where needed.
+ // this rewrite is used by both the general code and the next optimization.
+ for(l=sel->list; l; l=l->next) {
+ cas = l->n;
+ n = cas->left;
+ if(n == N)
+ continue;
+ switch(n->op) {
+ case OSELRECV:
+ ch = n->right->left;
+
+ // If we can use the address of the target without
+ // violating addressability or order of operations, do so.
+ // Otherwise introduce a temporary.
+ // Also introduce a temporary for := variables that escape,
+ // so that we can delay the heap allocation until the case
+ // is selected.
+ if(n->left == N || isblank(n->left))
+ n->left = nodnil();
+ else if(n->left->op == ONAME &&
+ (!n->colas || (n->class&PHEAP) == 0) &&
+ convertop(ch->type->type, n->left->type, nil) == OCONVNOP) {
+ n->left = nod(OADDR, n->left, N);
+ n->left->etype = 1; // pointer does not escape
+ typecheck(&n->left, Erv);
+ } else {
+ tmp = nod(OXXX, N, N);
+ tempname(tmp, ch->type->type);
+ a = nod(OADDR, tmp, N);
+ a->etype = 1; // pointer does not escape
+ typecheck(&a, Erv);
+ r = nod(OAS, n->left, tmp);
+ typecheck(&r, Etop);
+ cas->nbody = concat(n->ninit, cas->nbody);
+ n->ninit = nil;
+ cas->nbody = concat(list1(r), cas->nbody);
+ n->left = a;
+ }
+ }
+ }
+
+ // optimization: two-case select but one is default: single non-blocking op.
+ if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
+ if(sel->list->n->left == nil) {
+ cas = sel->list->next->n;
+ dflt = sel->list->n;
+ } else {
+ dflt = sel->list->next->n;
+ cas = sel->list->n;
+ }
+
+ n = cas->left;
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // if c != nil && selectnbsend(c, v) { body } else { default body }
+ ch = cheapexpr(n->left, &r->ninit);
+ r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
+ mkcall1(chanfn("selectnbsend", 2, ch->type),
+ types[TBOOL], &r->ninit, ch, n->right));
+ break;
+
+ case OSELRECV:
+ // if c != nil && selectnbrecv(&v, c) { body } else { default body }
+ r = nod(OIF, N, N);
+ r->ninit = cas->ninit;
+ ch = cheapexpr(n->right->left, &r->ninit);
+ r->ntest = nod(OANDAND, nod(ONE, ch, nodnil()),
+ mkcall1(chanfn("selectnbrecv", 2, ch->type),
+ types[TBOOL], &r->ninit, n->left, ch));
+ break;
+ }
+ typecheck(&r->ntest, Erv);
+ r->nbody = cas->nbody;
+ r->nelse = concat(dflt->ninit, dflt->nbody);
+ sel->nbody = list1(r);
+ goto out;
+ }
+
init = sel->ninit;
sel->ninit = nil;
@@ -96,16 +230,13 @@ walkselect(Node *sel)
typecheck(&r, Etop);
init = list(init, r);
- if(sel->list == nil && sel->xoffset != 0)
- fatal("double walkselect"); // already rewrote
-
// register cases
for(l=sel->list; l; l=l->next) {
- ncase = l->n;
- n = ncase->left;
+ cas = l->n;
+ n = cas->left;
r = nod(OIF, N, N);
- r->nbody = ncase->ninit;
- ncase->ninit = nil;
+ r->nbody = cas->ninit;
+ cas->ninit = nil;
if(n != nil) {
r->nbody = concat(r->nbody, n->ninit);
n->ninit = nil;
@@ -113,29 +244,24 @@ walkselect(Node *sel)
if(n == nil) {
// selectdefault(sel *byte);
r->ntest = mkcall("selectdefault", types[TBOOL], &init, var);
- } else if(n->op == OSEND) {
- // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
- r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], &init, var, n->left, n->right);
- } else if(n->op == OSELRECV) {
- tmp = N;
- if(n->left == N)
- a = nodnil();
- else {
- // introduce temporary until we're sure this will succeed.
- tmp = nod(OXXX, N, N);
- tempname(tmp, n->right->type->type);
- a = nod(OADDR, tmp, N);
- }
- // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
- r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->type), types[TBOOL], &init, var, n->right, a);
- if(tmp != N) {
- a = nod(OAS, n->left, tmp);
- typecheck(&a, Etop);
- r->nbody = list(r->nbody, a);
+ } else {
+ switch(n->op) {
+ default:
+ fatal("select %O", n->op);
+
+ case OSEND:
+ // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
+ &init, var, n->left, n->right);
+ break;
+ case OSELRECV:
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
+ &init, var, n->right->left, n->left);
+ break;
}
- } else
- fatal("select %O", n->op);
- r->nbody = concat(r->nbody, ncase->nbody);
+ }
+ r->nbody = concat(r->nbody, cas->nbody);
r->nbody = list(r->nbody, nod(OBREAK, N, N));
init = list(init, r);
}
@@ -143,8 +269,9 @@ walkselect(Node *sel)
// run the select
init = list(init, mkcall("selectgo", T, nil, var));
sel->nbody = init;
- sel->list = nil;
- walkstmtlist(init);
+out:
+ sel->list = nil;
+ walkstmtlist(sel->nbody);
lineno = lno;
}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 19ee3327b..31781646d 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -94,7 +94,7 @@ init1(Node *n, NodeList **out)
case OAS2FUNC:
case OAS2MAPR:
case OAS2DOTTYPE:
- case OAS2RECV:
+ case OAS2RECVCLOSED:
if(n->defn->initorder)
break;
n->defn->initorder = 1;
@@ -917,14 +917,12 @@ gen_as_init(Node *n)
case TPTR64:
case TFLOAT32:
case TFLOAT64:
- case TFLOAT:
gused(N); // in case the data is the dest of a goto
gdata(&nam, nr, nr->type->width);
break;
case TCOMPLEX64:
case TCOMPLEX128:
- case TCOMPLEX:
gused(N); // in case the data is the dest of a goto
gdatacomplex(&nam, nr->val.u.cval);
break;
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 3c4501096..cb5e2a831 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -836,7 +836,7 @@ goopnames[] =
[OCASE] = "case",
[OCLOSED] = "closed",
[OCLOSE] = "close",
- [OCMPLX] = "cmplx",
+ [OCOMPLEX] = "complex",
[OCOM] = "^",
[OCONTINUE] = "continue",
[OCOPY] = "copy",
@@ -993,10 +993,8 @@ etnames[] =
[TINT64] = "INT64",
[TUINT64] = "UINT64",
[TUINTPTR] = "UINTPTR",
- [TFLOAT] = "FLOAT",
[TFLOAT32] = "FLOAT32",
[TFLOAT64] = "FLOAT64",
- [TCOMPLEX] = "COMPLEX",
[TCOMPLEX64] = "COMPLEX64",
[TCOMPLEX128] = "COMPLEX128",
[TBOOL] = "BOOL",
@@ -1117,10 +1115,8 @@ basicnames[] =
[TINT64] = "int64",
[TUINT64] = "uint64",
[TUINTPTR] = "uintptr",
- [TFLOAT] = "float",
[TFLOAT32] = "float32",
[TFLOAT64] = "float64",
- [TCOMPLEX] = "complex",
[TCOMPLEX64] = "complex64",
[TCOMPLEX128] = "complex128",
[TBOOL] = "bool",
@@ -1752,8 +1748,6 @@ int
cplxsubtype(int et)
{
switch(et) {
- case TCOMPLEX:
- return TFLOAT;
case TCOMPLEX64:
return TFLOAT32;
case TCOMPLEX128:
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index ca114d47c..931d0327a 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -18,7 +18,7 @@ static int onearg(Node*, char*, ...);
static int twoarg(Node*);
static int lookdot(Node*, Type*, int);
static int looktypedot(Node*, Type*, int);
-static void typecheckaste(int, int, Type*, NodeList*, char*);
+static void typecheckaste(int, Node*, int, Type*, NodeList*, char*);
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
@@ -56,6 +56,34 @@ typechecklist(NodeList *l, int top)
typecheck(&l->n, top);
}
+static char* typekind[] = {
+ [TINT] = "int",
+ [TUINT] = "uint",
+ [TINT8] = "int8",
+ [TUINT8] = "uint8",
+ [TINT16] = "int16",
+ [TUINT16] = "uint16",
+ [TINT32] = "int32",
+ [TUINT32] = "uint32",
+ [TINT64] = "int64",
+ [TUINT64] = "uint64",
+ [TUINTPTR] = "uintptr",
+ [TCOMPLEX64] = "complex64",
+ [TCOMPLEX128] = "complex128",
+ [TFLOAT32] = "float32",
+ [TFLOAT64] = "float64",
+ [TBOOL] = "bool",
+ [TSTRING] = "string",
+ [TPTR32] = "pointer",
+ [TPTR64] = "pointer",
+ [TSTRUCT] = "struct",
+ [TINTER] = "interface",
+ [TCHAN] = "chan",
+ [TMAP] = "map",
+ [TARRAY] = "array",
+ [TFUNC] = "func",
+};
+
/*
* type check node *np.
* replaces *np with a new pointer in some cases.
@@ -372,21 +400,25 @@ reswitch:
et = t->etype;
}
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
- badbinary:
defaultlit2(&l, &r, 1);
- yyerror("invalid operation: %#N (type %T %#O %T)", n, l->type, op, r->type);
+ yyerror("invalid operation: %#N (mismatched types %T and %T)", n, l->type, r->type);
+ goto error;
+ }
+ if(!okfor[op][et]) {
+ notokfor:
+ yyerror("invalid operation: %#N (operator %#O not defined on %s)", n, op, typekind[et]);
goto error;
}
- if(!okfor[op][et])
- goto badbinary;
// okfor allows any array == array;
// restrict to slice == nil and nil == slice.
if(l->type->etype == TARRAY && !isslice(l->type))
- goto badbinary;
+ goto notokfor;
if(r->type->etype == TARRAY && !isslice(r->type))
- goto badbinary;
- if(isslice(l->type) && !isnil(l) && !isnil(r))
- goto badbinary;
+ goto notokfor;
+ if(isslice(l->type) && !isnil(l) && !isnil(r)) {
+ yyerror("invalid operation: %#N (slice can only be compared to nil)", n);
+ goto error;
+ }
t = l->type;
if(iscmp[n->op]) {
evconst(n);
@@ -472,7 +504,7 @@ reswitch:
l = n->left;
if((t = l->type) == T)
goto error;
- if(!(top & Eindir))
+ if(!(top & Eindir) && !n->etype)
addrescapes(n->left);
n->type = ptrto(t);
goto ret;
@@ -636,6 +668,10 @@ reswitch:
goto ret;
case OSEND:
+ if(top & Erv) {
+ yyerror("send statement %#N used as value; use select for non-blocking send", n);
+ goto error;
+ }
ok |= Etop | Erv;
l = typecheck(&n->left, Erv);
typecheck(&n->right, Erv);
@@ -659,10 +695,6 @@ reswitch:
// TODO: more aggressive
n->etype = 0;
n->type = T;
- if(top & Erv) {
- n->op = OSENDNB;
- n->type = types[TBOOL];
- }
goto ret;
case OSLICE:
@@ -769,7 +801,7 @@ reswitch:
case ODOTMETH:
n->op = OCALLMETH;
- typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver");
+ typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver");
break;
default:
@@ -780,7 +812,7 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument");
+ typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, "function argument");
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -852,7 +884,7 @@ reswitch:
n->type = types[TINT];
goto ret;
- case OCMPLX:
+ case OCOMPLEX:
ok |= Erv;
if(twoarg(n) < 0)
goto error;
@@ -865,7 +897,7 @@ reswitch:
n->right = r;
if(l->type->etype != r->type->etype) {
badcmplx:
- yyerror("invalid operation: %#N (cmplx of types %T, %T)", n, l->type, r->type);
+ yyerror("invalid operation: %#N (complex of types %T, %T)", n, l->type, r->type);
goto error;
}
switch(l->type->etype) {
@@ -874,9 +906,6 @@ reswitch:
case TIDEAL:
t = types[TIDEAL];
break;
- case TFLOAT:
- t = types[TCOMPLEX];
- break;
case TFLOAT32:
t = types[TCOMPLEX64];
break;
@@ -1217,7 +1246,7 @@ reswitch:
}
if(curfn->type->outnamed && n->list == nil)
goto ret;
- typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument");
+ typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
goto ret;
case OSELECT:
@@ -1562,7 +1591,7 @@ nokeys(NodeList *l)
* typecheck assignment: type list = expression list
*/
static void
-typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
+typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
{
Type *t, *tl, *tn;
Node *n;
@@ -1581,16 +1610,24 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
if(tl->isddd) {
for(; tn; tn=tn->down) {
exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type->type, &why) == 0)
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ if(assignop(tn->type, tl->type->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type->type, desc, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ }
}
goto out;
}
if(tn == T)
goto notenough;
exportassignok(tn->type, desc);
- if(assignop(tn->type, tl->type, &why) == 0)
- yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
+ if(assignop(tn->type, tl->type, &why) == 0) {
+ if(call != N)
+ yyerror("cannot use %T as type %T in argument to %#N%s", tn->type, tl->type, desc, call, why);
+ else
+ yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
+ }
tn = tn->down;
}
if(tn != T)
@@ -1635,19 +1672,29 @@ typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
}
if(nl != nil)
goto toomany;
- if(isddd)
- yyerror("invalid use of ... in %#O", op);
+ if(isddd) {
+ if(call != N)
+ yyerror("invalid use of ... in call to %#N", call);
+ else
+ yyerror("invalid use of ... in %#O", op);
+ }
out:
lineno = lno;
return;
notenough:
- yyerror("not enough arguments to %#O", op);
+ if(call != N)
+ yyerror("not enough arguments in call to %#N", call);
+ else
+ yyerror("not enough arguments to %#O", op);
goto out;
toomany:
- yyerror("too many arguments to %#O", op);
+ if(call != N)
+ yyerror("too many arguments in call to %#N", call);
+ else
+ yyerror("too many arguments to %#O", op);
goto out;
}
@@ -2329,8 +2376,8 @@ typecheckas2(Node *n)
n->op = OAS2MAPR;
goto common;
case ORECV:
- n->op = OAS2RECV;
- goto common;
+ yyerror("cannot use multiple-value assignment for non-blocking receive; use select");
+ goto out;
case ODOTTYPE:
n->op = OAS2DOTTYPE;
r->op = ODOTTYPE2;
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index fa3e5d5e4..b32b6fff5 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -269,9 +269,15 @@ walkdef(Node *n)
}
t = n->type;
if(t != T) {
- convlit(&e, t);
- if(!okforconst[t->etype])
+ if(!okforconst[t->etype]) {
yyerror("invalid constant type %T", t);
+ goto ret;
+ }
+ if(!isideal(e->type) && !eqtype(t, e->type)) {
+ yyerror("cannot use %+N as type %T in const initializer", e, t);
+ goto ret;
+ }
+ convlit(&e, t);
}
n->val = e->val;
n->type = e->type;
@@ -397,7 +403,7 @@ walkstmt(Node **np)
case OAS:
case OAS2:
case OAS2DOTTYPE:
- case OAS2RECV:
+ case OAS2RECVCLOSED:
case OAS2FUNC:
case OAS2MAPW:
case OAS2MAPR:
@@ -664,7 +670,7 @@ walkexpr(Node **np, NodeList **init)
case OGE:
case OGT:
case OADD:
- case OCMPLX:
+ case OCOMPLEX:
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
@@ -816,14 +822,14 @@ walkexpr(Node **np, NodeList **init)
n = liststmt(concat(concat(list1(r), ll), lpost));
goto ret;
- case OAS2RECV:
- // a,b = <-c
+ case OAS2RECVCLOSED:
+ // a = <-c; b = closed(c) but atomic
*init = concat(*init, n->ninit);
n->ninit = nil;
r = n->rlist->n;
walkexprlistsafe(n->list, init);
walkexpr(&r->left, init);
- fn = chanfn("chanrecv2", 2, r->left->type);
+ fn = chanfn("chanrecv3", 2, r->left->type);
r = mkcall1(fn, getoutargx(fn->type), init, r->left);
n->rlist->n = r;
n->op = OAS2FUNC;
@@ -1401,10 +1407,6 @@ walkexpr(Node **np, NodeList **init)
n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, n->left, n->right);
goto ret;
- case OSENDNB:
- n = mkcall1(chanfn("chansend2", 2, n->left->type), n->type, init, n->left, n->right);
- goto ret;
-
case OCLOSURE:
n = walkclosure(n, init);
goto ret;
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
index 69ee1be5d..d4163421d 100644
--- a/src/cmd/godefs/main.c
+++ b/src/cmd/godefs/main.c
@@ -196,7 +196,7 @@ main(int argc, char **argv)
av[n++] = "gcc";
av[n++] = "-fdollars-in-identifiers";
av[n++] = "-S"; // write assembly
- av[n++] = "-gstabs"; // include stabs info
+ av[n++] = "-gstabs+"; // include stabs info
av[n++] = "-o"; // to ...
av[n++] = "-"; // ... stdout
av[n++] = "-xc"; // read C
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
index 1bc96d4c8..f2bb57eb6 100644
--- a/src/cmd/godefs/stabs.c
+++ b/src/cmd/godefs/stabs.c
@@ -102,6 +102,23 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p)
return 0;
}
+// Written to parse max/min of vlong correctly.
+static vlong
+parseoctal(char **pp)
+{
+ char *p;
+ vlong n;
+
+ p = *pp;
+ if(*p++ != '0')
+ return 0;
+ n = 0;
+ while(*p >= '0' && *p <= '9')
+ n = n << 3 | *p++ - '0';
+ *pp = p;
+ return n;
+}
+
// Integer types are represented in stabs as a "range"
// type with a lo and a hi value. The lo and hi used to
// be lo and hi for the type, but there are now odd
@@ -112,31 +129,24 @@ parsetypenum(char **pp, vlong *n1p, vlong *n2p)
typedef struct Intrange Intrange;
struct Intrange
{
- int signlo; // sign of lo
vlong lo;
- int signhi; // sign of hi
vlong hi;
int kind;
};
-// NOTE(rsc): Iant says that these might be different depending
-// on the gcc mode, though I haven't observed this yet.
Intrange intranges[] = {
- '+', 0, '+', 127, Int8, // char
- '-', 128, '+', 127, Int8, // signed char
- '+', 0, '+', 255, Uint8,
- '-', 32768, '+', 32767, Int16,
- '+', 0, '+', 65535, Uint16,
- '-', 2147483648LL, '+', 2147483647LL, Int32,
- '+', 0, '+', 4294967295LL, Uint32,
-
- // abnormal cases
- '-', 0, '+', 4294967295LL, Int64,
- '+', 0, '-', 1, Uint64,
-
- '+', 4, '+', 0, Float32,
- '+', 8, '+', 0, Float64,
- '+', 16, '+', 0, Void,
+ 0, 127, Int8, // char
+ -128, 127, Int8, // signed char
+ 0, 255, Uint8,
+ -32768, 32767, Int16,
+ 0, 65535, Uint16,
+ -2147483648LL, 2147483647LL, Int32,
+ 0, 4294967295LL, Uint32,
+ 1LL << 63, ~(1LL << 63), Int64,
+ 0, -1, Uint64,
+ 4, 0, Float32,
+ 8, 0, Float64,
+ 16, 0, Void,
};
static int kindsize[] = {
@@ -158,7 +168,7 @@ parsedef(char **pp, char *name)
{
char *p;
Type *t, *tt;
- int i, signlo, signhi;
+ int i;
vlong n1, n2, lo, hi;
Field *f;
Intrange *r;
@@ -213,6 +223,11 @@ parsedef(char **pp, char *name)
*pp = "";
return t;
+ case '@': // type attribute
+ while (*++p != ';');
+ *pp = ++p;
+ return parsedef(pp, nil);
+
case '*': // pointer
p++;
t->kind = Ptr;
@@ -269,6 +284,10 @@ parsedef(char **pp, char *name)
return nil;
break;
+ case 'k': // const
+ ++*pp;
+ return parsedef(pp, nil);
+
case 'r': // sub-range (used for integers)
p++;
if(parsedef(&p, nil) == nil)
@@ -280,23 +299,19 @@ parsedef(char **pp, char *name)
fprint(2, "range expected number: %s\n", p);
return nil;
}
- if(*p == '-') {
- signlo = '-';
- p++;
- } else
- signlo = '+';
- lo = strtoll(p, &p, 10);
+ if(*p == '0')
+ lo = parseoctal(&p);
+ else
+ lo = strtoll(p, &p, 10);
if(*p != ';' || *++p == ';') {
if(stabsdebug)
fprint(2, "range expected number: %s\n", p);
return nil;
}
- if(*p == '-') {
- signhi = '-';
- p++;
- } else
- signhi = '+';
- hi = strtoll(p, &p, 10);
+ if(*p == '0')
+ hi = parseoctal(&p);
+ else
+ hi = strtoll(p, &p, 10);
if(*p != ';') {
if(stabsdebug)
fprint(2, "range expected trailing semi: %s\n", p);
@@ -306,7 +321,7 @@ parsedef(char **pp, char *name)
t->size = hi+1; // might be array size
for(i=0; i<nelem(intranges); i++) {
r = &intranges[i];
- if(r->signlo == signlo && r->signhi == signhi && r->lo == lo && r->hi == hi) {
+ if(r->lo == lo && r->hi == hi) {
t->kind = r->kind;
break;
}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 02779384c..f0006e750 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -47,8 +47,9 @@ The flags are:
width of tabs in units of spaces
-timestamps=true
show timestamps with directory listings
- -fulltext=false
- build full text index for regular expression queries
+ -maxresults=10000
+ maximum number of full text search results shown
+ (no full text index is built if maxresults <= 0)
-path=""
additional package directories (colon-separated)
-html
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
index f68c67b24..66b01aa64 100644
--- a/src/cmd/godoc/format.go
+++ b/src/cmd/godoc/format.go
@@ -62,12 +62,48 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection,
if lw != nil {
selections = append(selections, links)
}
+
// compute the sequence of consecutive segment changes
changes := newMerger(selections)
+
// The i'th bit in bitset indicates that the text
// at the current offset is covered by selections[i].
bitset := 0
lastOffs := 0
+
+ // Text segments are written in a delayed fashion
+ // such that consecutive segments belonging to the
+ // same selection can be combined (peephole optimization).
+ // last describes the last segment which has not yet been written.
+ var last struct {
+ begin, end int // valid if begin < end
+ bitset int
+ }
+
+ // flush writes the last delayed text segment
+ flush := func() {
+ if last.begin < last.end {
+ sw(w, text[last.begin:last.end], last.bitset)
+ }
+ last.begin = last.end // invalidate last
+ }
+
+ // segment runs the segment [lastOffs, end) with the selection
+ // indicated by bitset through the segment peephole optimizer.
+ segment := func(end int) {
+ if lastOffs < end { // ignore empty segments
+ if last.end != lastOffs || last.bitset != bitset {
+ // the last segment is not adjacent to or
+ // differs from the new one
+ flush()
+ // start a new segment
+ last.begin = lastOffs
+ }
+ last.end = end
+ last.bitset = bitset
+ }
+ }
+
for {
// get the next segment change
index, offs, start := changes.next()
@@ -81,14 +117,15 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection,
// we have a link segment change:
// format the previous selection segment, write the
// link tag and start a new selection segment
- sw(w, text[lastOffs:offs], bitset)
+ segment(offs)
+ flush()
lastOffs = offs
lw(w, offs, start)
} else {
// we have a selection change:
// format the previous selection segment, determine
// the new selection bitset and start a new segment
- sw(w, text[lastOffs:offs], bitset)
+ segment(offs)
lastOffs = offs
mask := 1 << uint(index)
if start {
@@ -98,7 +135,8 @@ func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection,
}
}
}
- sw(w, text[lastOffs:], bitset)
+ segment(len(text))
+ flush()
}
@@ -201,7 +239,9 @@ func lineSelection(text []byte) Selection {
//
func commentSelection(src []byte) Selection {
var s scanner.Scanner
- file := s.Init(token.NewFileSet(), "", src, nil, scanner.ScanComments+scanner.InsertSemis)
+ fset := token.NewFileSet()
+ file := fset.AddFile("", fset.Base(), len(src))
+ s.Init(file, src, nil, scanner.ScanComments+scanner.InsertSemis)
return func() (seg []int) {
for {
pos, tok, lit := s.Scan()
@@ -283,17 +323,15 @@ var endTag = []byte(`</span>`)
func selectionTag(w io.Writer, text []byte, selections int) {
- if len(text) > 0 {
- if selections < len(startTags) {
- if tag := startTags[selections]; len(tag) > 0 {
- w.Write(tag)
- template.HTMLEscape(w, text)
- w.Write(endTag)
- return
- }
+ if selections < len(startTags) {
+ if tag := startTags[selections]; len(tag) > 0 {
+ w.Write(tag)
+ template.HTMLEscape(w, text)
+ w.Write(endTag)
+ return
}
- template.HTMLEscape(w, text)
}
+ template.HTMLEscape(w, text)
}
@@ -322,12 +360,12 @@ func FormatText(text []byte, line int, goSource bool, pattern string, selection
if pattern != "" {
highlights = regexpSelection(text, pattern)
}
- if comments != nil || highlights != nil || selection != nil {
+ if line >= 0 || comments != nil || highlights != nil || selection != nil {
var lineTag LinkWriter
if line >= 0 {
lineTag = func(w io.Writer, _ int, start bool) {
if start {
- fmt.Fprintf(w, "<a id=\"L%d\"></a>%5d\t", line, line)
+ fmt.Fprintf(w, "<a id=\"L%d\"></a><span class=\"ln\">%6d</span>\t", line, line)
line++
}
}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index d6054ab9d..6a00a3e70 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -25,7 +25,6 @@ import (
"strings"
"template"
"time"
- "utf8"
)
@@ -56,7 +55,7 @@ var (
// TODO(gri) consider the invariant that goroot always end in '/'
goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
testDir = flag.String("testdir", "", "Go root subdirectory - for testing only (faster startups)")
- path = flag.String("path", "", "additional package directories (colon-separated)")
+ pkgPath = flag.String("path", "", "additional package directories (colon-separated)")
filter = flag.String("filter", "", "filter file containing permitted package directory paths")
filterMin = flag.Int("filter_minutes", 0, "filter file update interval in minutes; disabled if <= 0")
filterDelay delayTime // actual filter update interval in minutes; usually filterDelay == filterMin, but filterDelay may back off exponentially
@@ -64,7 +63,7 @@ var (
// layout control
tabwidth = flag.Int("tabwidth", 4, "tab width")
showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
- fulltextIndex = flag.Bool("fulltext", false, "build full text index for regular expression queries")
+ maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
// file system mapping
fsMap Mapping // user-defined mapping
@@ -80,7 +79,7 @@ var (
func initHandlers() {
- fsMap.Init(*path)
+ fsMap.Init(*pkgPath)
fileServer = http.FileServer(*goroot, "")
cmdHandler = httpHandler{"/cmd/", pathutil.Join(*goroot, "src/cmd"), false}
pkgHandler = httpHandler{"/pkg/", pathutil.Join(*goroot, "src/pkg"), true}
@@ -626,11 +625,11 @@ func readTemplate(name string) *template.Template {
path := pathutil.Join(*goroot, "lib/godoc/"+name)
data, err := ioutil.ReadFile(path)
if err != nil {
- log.Exitf("ReadFile %s: %v", path, err)
+ log.Fatalf("ReadFile %s: %v", path, err)
}
t, err := template.Parse(string(data), fmap)
if err != nil {
- log.Exitf("%s: %v", name, err)
+ log.Fatalf("%s: %v", name, err)
}
return t
}
@@ -768,53 +767,6 @@ func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
}
-// TODO(gri): Should have a mapping from extension to handler, eventually.
-
-// textExt[x] is true if the extension x indicates a text file, and false otherwise.
-var textExt = map[string]bool{
- ".css": false, // must be served raw
- ".js": false, // must be served raw
-}
-
-
-func isTextFile(path string) bool {
- // if the extension is known, use it for decision making
- if isText, found := textExt[pathutil.Ext(path)]; found {
- return isText
- }
-
- // the extension is not known; read an initial chunk of
- // file and check if it looks like correct UTF-8; if it
- // does, it's probably a text file
- f, err := os.Open(path, os.O_RDONLY, 0)
- if err != nil {
- return false
- }
- defer f.Close()
-
- var buf [1024]byte
- n, err := f.Read(buf[0:])
- if err != nil {
- return false
- }
-
- s := string(buf[0:n])
- n -= utf8.UTFMax // make sure there's enough bytes for a complete unicode char
- for i, c := range s {
- if i > n {
- break
- }
- if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
- // decoding error or control character - not a text file
- return false
- }
- }
-
- // likely a text file
- return true
-}
-
-
func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
src, err := ioutil.ReadFile(abspath)
if err != nil {
@@ -1159,41 +1111,47 @@ type SearchResult struct {
func lookup(query string) (result SearchResult) {
result.Query = query
- // determine identifier lookup string and full text regexp
- lookupStr := ""
- lookupRx, err := regexp.Compile(query)
- if err != nil {
- result.Alert = "Error in query regular expression: " + err.String()
- return
- }
- if prefix, complete := lookupRx.LiteralPrefix(); complete {
- // otherwise we lookup "" (with no result) because
- // identifier lookup doesn't support regexp search
- lookupStr = prefix
- }
+ index, timestamp := searchIndex.get()
+ if index != nil {
+ index := index.(*Index)
- if index, timestamp := searchIndex.get(); index != nil {
// identifier search
- index := index.(*Index)
- result.Hit, result.Alt, err = index.Lookup(lookupStr)
- if err != nil && !*fulltextIndex {
- // ignore the error if there is full text search
- // since it accepts that query regular expression
+ var err os.Error
+ result.Hit, result.Alt, err = index.Lookup(query)
+ if err != nil && *maxResults <= 0 {
+ // ignore the error if full text search is enabled
+ // since the query may be a valid regular expression
result.Alert = "Error in query string: " + err.String()
return
}
- // textual search
- // TODO(gri) should max be a flag?
- const max = 10000 // show at most this many fulltext results
- result.Found, result.Textual = index.LookupRegexp(lookupRx, max+1)
- result.Complete = result.Found <= max
-
- // is the result accurate?
- if _, ts := fsModified.get(); timestamp < ts {
- result.Alert = "Indexing in progress: result may be inaccurate"
+ // full text search
+ if *maxResults > 0 && query != "" {
+ rx, err := regexp.Compile(query)
+ if err != nil {
+ result.Alert = "Error in query regular expression: " + err.String()
+ return
+ }
+ // If we get maxResults+1 results we know that there are more than
+ // maxResults results and thus the result may be incomplete (to be
+ // precise, we should remove one result from the result set, but
+ // nobody is going to count the results on the result page).
+ result.Found, result.Textual = index.LookupRegexp(rx, *maxResults+1)
+ result.Complete = result.Found <= *maxResults
+ if !result.Complete {
+ result.Found-- // since we looked for maxResults+1
+ }
}
}
+
+ // is the result accurate?
+ if _, ts := fsModified.get(); timestamp < ts {
+ // The index is older than the latest file system change
+ // under godoc's observation. Indexing may be in progress
+ // or start shortly (see indexer()).
+ result.Alert = "Indexing in progress: result may be inaccurate"
+ }
+
return
}
@@ -1278,7 +1236,7 @@ func indexer() {
log.Printf("updating index...")
}
start := time.Nanoseconds()
- index := NewIndex(fsDirnames(), *fulltextIndex)
+ index := NewIndex(fsDirnames(), *maxResults > 0)
stop := time.Nanoseconds()
searchIndex.set(index)
if *verbose {
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index ba6fe9acd..581409cde 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -47,7 +47,7 @@ import (
"index/suffixarray"
"io/ioutil"
"os"
- pathutil "path"
+ "path"
"regexp"
"sort"
"strings"
@@ -430,8 +430,9 @@ func (a *AltWords) filter(s string) *AltWords {
// Indexer
// Adjust these flags as seems best.
-const excludeMainPackages = false
-const excludeTestFiles = false
+const includeNonGoFiles = true
+const includeMainPackages = true
+const includeTestFiles = true
type IndexResult struct {
@@ -619,11 +620,14 @@ func pkgName(filename string) string {
}
-func (x *Indexer) addFile(filename string) *ast.File {
+// addFile adds a file to the index if possible and returns the file set file
+// and the file's AST if it was successfully parsed as a Go file. If addFile
+// failed (that is, if the file was not added), it returns file == nil.
+func (x *Indexer) addFile(filename string, goFile bool) (file *token.File, ast *ast.File) {
// open file
f, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil {
- return nil
+ return
}
defer f.Close()
@@ -643,59 +647,127 @@ func (x *Indexer) addFile(filename string) *ast.File {
panic("internal error - file base incorrect")
}
- // append file contents to x.sources
- if _, err := x.sources.ReadFrom(f); err != nil {
- x.sources.Truncate(base) // discard possibly added data
- return nil // ignore files with I/O errors
- }
+ // append file contents (src) to x.sources
+ if _, err := x.sources.ReadFrom(f); err == nil {
+ src := x.sources.Bytes()[base:]
- // parse the file and in the process add it to the file set
- src := x.sources.Bytes()[base:] // no need to reread the file
- file, err := parser.ParseFile(x.fset, filename, src, parser.ParseComments)
- if err != nil {
- // do not discard the added source code in this case
- // because the file has been added to the file set and
- // the source size must match the file set base
- // TODO(gri): given a FileSet.RemoveFile() one might be
- // able to discard the data here (worthwhile?)
- return nil // ignore files with (parse) errors
+ if goFile {
+ // parse the file and in the process add it to the file set
+ if ast, err = parser.ParseFile(x.fset, filename, src, parser.ParseComments); err == nil {
+ file = x.fset.File(ast.Pos()) // ast.Pos() is inside the file
+ return
+ }
+ // file has parse errors, and the AST may be incorrect -
+ // set lines information explicitly and index as ordinary
+ // text file (cannot fall through to the text case below
+ // because the file has already been added to the file set
+ // by the parser)
+ file = x.fset.File(token.Pos(base)) // token.Pos(base) is inside the file
+ file.SetLinesForContent(src)
+ ast = nil
+ return
+ }
+
+ if isText(src) {
+ // only add the file to the file set (for the full text index)
+ file = x.fset.AddFile(filename, x.fset.Base(), len(src))
+ file.SetLinesForContent(src)
+ return
+ }
}
- return file
+ // discard possibly added data
+ x.sources.Truncate(base - 1) // -1 to remove added byte 0 since no file was added
+ return
}
-func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
- if !isGoFile(f) {
- return
+// Design note: Using an explicit white list of permitted files for indexing
+// makes sure that the important files are included and massively reduces the
+// number of files to index. The advantage over a blacklist is that unexpected
+// (non-blacklisted) files won't suddenly explode the index.
+//
+// TODO(gri): We may want to make this list customizable, perhaps via a flag.
+
+// Files are whitelisted if they have a file name or extension
+// present as key in whitelisted.
+var whitelisted = map[string]bool{
+ ".bash": true,
+ ".c": true,
+ ".css": true,
+ ".go": true,
+ ".goc": true,
+ ".h": true,
+ ".html": true,
+ ".js": true,
+ ".out": true,
+ ".py": true,
+ ".s": true,
+ ".sh": true,
+ ".txt": true,
+ ".xml": true,
+ "AUTHORS": true,
+ "CONTRIBUTORS": true,
+ "LICENSE": true,
+ "Makefile": true,
+ "PATENTS": true,
+ "README": true,
+}
+
+
+// isWhitelisted returns true if a file is on the list
+// of "permitted" files for indexing. The filename must
+// be the directory-local name of the file.
+func isWhitelisted(filename string) bool {
+ key := path.Ext(filename)
+ if key == "" {
+ // file has no extension - use entire filename
+ key = filename
}
+ return whitelisted[key]
+}
- path := pathutil.Join(dirname, f.Name)
- if excludeTestFiles && (!isPkgFile(f) || strings.HasPrefix(path, "test/")) {
+
+func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
+ if !f.IsRegular() {
return
}
- if excludeMainPackages && pkgName(path) == "main" {
+ filename := path.Join(dirname, f.Name)
+ goFile := false
+
+ switch {
+ case isGoFile(f):
+ if !includeTestFiles && (!isPkgFile(f) || strings.HasPrefix(filename, "test/")) {
+ return
+ }
+ if !includeMainPackages && pkgName(filename) == "main" {
+ return
+ }
+ goFile = true
+
+ case !includeNonGoFiles || !isWhitelisted(f.Name):
return
}
- file := x.addFile(path)
+ file, fast := x.addFile(filename, goFile)
if file == nil {
- return
+ return // addFile failed
}
- // we've got a file to index
- x.current = x.fset.File(file.Pos()) // file.Pos is in the current file
- dir, _ := pathutil.Split(path)
- pak := Pak{dir, file.Name.Name}
- x.file = &File{path, pak}
- ast.Walk(x, file)
+ if fast != nil {
+ // we've got a Go file to index
+ x.current = file
+ dir, _ := path.Split(filename)
+ pak := Pak{dir, fast.Name.Name}
+ x.file = &File{filename, pak}
+ ast.Walk(x, fast)
+ }
// update statistics
- // (count real file size as opposed to using the padded x.sources.Len())
- x.stats.Bytes += x.current.Size()
+ x.stats.Bytes += file.Size()
x.stats.Files++
- x.stats.Lines += x.current.LineCount()
+ x.stats.Lines += file.LineCount()
}
@@ -817,7 +889,8 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
func isIdentifier(s string) bool {
var S scanner.Scanner
- S.Init(token.NewFileSet(), "", []byte(s), nil, 0)
+ fset := token.NewFileSet()
+ S.Init(fset.AddFile("", fset.Base(), len(s)), []byte(s), nil, 0)
if _, tok, _ := S.Scan(); tok == token.IDENT {
_, tok, _ := S.Scan()
return tok == token.EOF
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index fe3d22fb9..f1b11a760 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -227,7 +227,7 @@ func main() {
}
if *tabwidth < 0 {
- log.Exitf("negative tabwidth %d", *tabwidth)
+ log.Fatalf("negative tabwidth %d", *tabwidth)
}
initHandlers()
@@ -242,8 +242,8 @@ func main() {
log.Printf("address = %s", *httpAddr)
log.Printf("goroot = %s", *goroot)
log.Printf("tabwidth = %d", *tabwidth)
- if *fulltextIndex {
- log.Print("full text index enabled")
+ if *maxResults > 0 {
+ log.Printf("maxresults = %d (full text index enabled)", *maxResults)
}
if !fsMap.IsEmpty() {
log.Print("user-defined mapping:")
@@ -284,7 +284,7 @@ func main() {
// Start http server.
if err := http.ListenAndServe(*httpAddr, handler); err != nil {
- log.Exitf("ListenAndServe %s: %v", *httpAddr, err)
+ log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
}
return
@@ -301,7 +301,7 @@ func main() {
for i := 0; i < flag.NArg(); i++ {
res, err := remoteSearch(flag.Arg(i))
if err != nil {
- log.Exitf("remoteSearch: %s", err)
+ log.Fatalf("remoteSearch: %s", err)
}
io.Copy(os.Stdout, res.Body)
}
@@ -344,7 +344,7 @@ func main() {
info = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
if info.Err != nil {
- log.Exitf("%v", info.Err)
+ log.Fatalf("%v", info.Err)
}
// If we have more than one argument, use the remaining arguments for filtering
@@ -352,7 +352,7 @@ func main() {
args := flag.Args()[1:]
rx := makeRx(args)
if rx == nil {
- log.Exitf("illegal regular expression from %v", args)
+ log.Fatalf("illegal regular expression from %v", args)
}
filter := func(s string) bool { return rx.MatchString(s) }
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
index 6a12febe1..c2838ed5a 100755
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -26,7 +26,7 @@ type Snippet struct {
func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
// TODO instead of pretty-printing the node, should use the original source instead
var buf bytes.Buffer
- writeNode(&buf, fset, decl, true)
+ writeNode(&buf, fset, decl, false)
return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)}
}
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index b1c1a883f..a533c1e0a 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -156,7 +156,8 @@ func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
// initialize ebnfParser
p.out = out
p.src = src
- p.file = p.scanner.Init(fset, "", src, p, 0)
+ p.file = fset.AddFile("", fset.Base(), len(src))
+ p.scanner.Init(p.file, src, p, 0)
p.next() // initializes pos, tok, lit
// process source
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
index 55cf87841..a032bd331 100644
--- a/src/cmd/godoc/utils.go
+++ b/src/cmd/godoc/utils.go
@@ -15,11 +15,13 @@ import (
"strings"
"sync"
"time"
+ "utf8"
)
// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
+//
type RWValue struct {
mutex sync.RWMutex
value interface{}
@@ -107,3 +109,63 @@ func writeFileAtomically(filename string, data []byte) os.Error {
}
return os.Rename(f.Name(), filename)
}
+
+
+// isText returns true if a significant prefix of s looks like correct UTF-8;
+// that is, if it is likely that s is human-readable text.
+//
+func isText(s []byte) bool {
+ const max = 1024 // at least utf8.UTFMax
+ if len(s) > max {
+ s = s[0:max]
+ }
+ for i, c := range string(s) {
+ if i+utf8.UTFMax > len(s) {
+ // last char may be incomplete - ignore
+ break
+ }
+ if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
+ // decoding error or control character - not a text file
+ return false
+ }
+ }
+ return true
+}
+
+
+// TODO(gri): Should have a mapping from extension to handler, eventually.
+
+// textExt[x] is true if the extension x indicates a text file, and false otherwise.
+var textExt = map[string]bool{
+ ".css": false, // must be served raw
+ ".js": false, // must be served raw
+}
+
+
+// isTextFile returns true if the file has a known extension indicating
+// a text file, or if a significant chunk of the specified file looks like
+// correct UTF-8; that is, if it is likely that the file contains human-
+// readable text.
+//
+func isTextFile(filename string) bool {
+ // if the extension is known, use it for decision making
+ if isText, found := textExt[pathutil.Ext(filename)]; found {
+ return isText
+ }
+
+ // the extension is not known; read an initial chunk
+ // of the file and check if it looks like text
+ f, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ return false
+ }
+ defer f.Close()
+
+ var buf [1024]byte
+ n, err := f.Read(buf[0:])
+ if err != nil {
+ return false
+ }
+
+ return isText(buf[0:n])
+}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 8ea5334e9..fbcd46aa2 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -124,9 +124,9 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// Wildcard matches any expression. If it appears multiple
// times in the pattern, it must match the same expression
// each time.
- if m != nil && pattern.Type() == identType {
+ if m != nil && pattern != nil && pattern.Type() == identType {
name := pattern.Interface().(*ast.Ident).Name
- if isWildcard(name) {
+ if isWildcard(name) && val != nil {
// wildcards only match expressions
if _, ok := val.Interface().(ast.Expr); ok {
if old, ok := m[name]; ok {
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index b0f08efdf..f13aeb3bc 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -244,8 +244,7 @@ func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error {
bin, err := exec.LookPath(cmd[0])
if err != nil {
- // report binary as well as the error
- return os.NewError(cmd[0] + ": " + err.String())
+ return err
}
p, err := exec.Run(bin, cmd, os.Environ(), dir, exec.Pipe, exec.Pipe, exec.MergeWithStdout)
if *verbose {
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index 063967bd7..a16e98cfe 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -607,6 +607,7 @@ scanobj(Biobuf *b, Arfile *ap, long size)
/* maybe a foreign object file? that's okay */
if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF
+ (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE
(buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian
(buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian
Bseek(b, offset, 0);
diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest
index 7572610d2..87c680089 100755
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -180,10 +180,4 @@ importpath=$(gomake -s importpath)
$GC _testmain.go
$GL _testmain.$O
-
-# Set dynamic linker library path, no matter what it's called,
-# to include the current directory while running $O.out,
-# so that cgo libraries can be tested without installation.
-LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH \
-DYLD_LIBRARY_PATH=.:$DYLD_LIBRARY_PATH \
$E ./$O.out "$@"
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
index 2981891eb..5619b12ba 100644
--- a/src/cmd/govet/govet.go
+++ b/src/cmd/govet/govet.go
@@ -210,6 +210,7 @@ var printfList = map[string]int{
"Errorf": 0,
"Fatalf": 0,
"Fprintf": 1,
+ "Panicf": 0,
"Printf": 0,
"Sprintf": 0,
}
@@ -220,6 +221,7 @@ var printList = map[string]int{
"Error": 0,
"Fatal": 0,
"Fprint": 1, "Fprintln": 1,
+ "Panic": 0, "Panicln": 0,
"Print": 0, "Println": 0,
"Sprint": 0, "Sprintln": 0,
}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 210f10ab5..0551232cf 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -240,6 +240,33 @@ void
dynrelocsym(Sym *s)
{
Reloc *r;
+
+ if(thechar == '8' && HEADTYPE == 10) { // Windows PE
+ Sym *rel, *targ;
+
+ rel = lookup(".rel", 0);
+ if(s == rel)
+ return;
+ for(r=s->r; r<s->r+s->nr; r++) {
+ targ = r->sym;
+ if(r->sym->plt == -2) { // make dynimport JMP table for PE object files.
+ targ->plt = rel->size;
+ r->sym = rel;
+ r->add = targ->plt;
+
+ // jmp *addr
+ adduint8(rel, 0xff);
+ adduint8(rel, 0x25);
+ addaddr(rel, targ);
+ adduint8(rel, 0x90);
+ adduint8(rel, 0x90);
+ } else if(r->sym->plt >= 0) {
+ r->sym = rel;
+ r->add = targ->plt;
+ }
+ }
+ return;
+ }
for(r=s->r; r<s->r+s->nr; r++)
if(r->sym->type == SDYNIMPORT || r->type >= 256)
@@ -871,7 +898,7 @@ address(void)
segdata.rwx = 06;
segdata.vaddr = va;
segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
- if(thechar == '8' && HEADTYPE == 10) // Windows PE
+ if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Windows PE
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
if(thechar == '8' && HEADTYPE == 2) { // Plan 9
segdata.vaddr = va = rnd(va, 4096);
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 506c6e5db..5df3515f5 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -19,6 +19,7 @@
#include "../ld/dwarf_defs.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/pe.h"
/*
* Offsets and sizes of the debug_* sections in the cout file.
@@ -453,19 +454,6 @@ getattr(DWDie *die, uint8 attr)
return nil;
}
-static void
-delattr(DWDie *die, uint8 attr)
-{
- DWAttr **a;
-
- a = &die->attr;
- while (*a != nil)
- if ((*a)->atr == attr)
- *a = (*a)->link;
- else
- a = &((*a)->link);
-}
-
// Every DIE has at least a DW_AT_name attribute (but it will only be
// written out if it is listed in the abbrev). If its parent is
// keeping an index, the new DIE will be inserted there.
@@ -768,10 +756,8 @@ enum {
KindUint32,
KindUint64,
KindUintptr,
- KindFloat,
KindFloat32,
KindFloat64,
- KindComplex,
KindComplex64,
KindComplex128,
KindArray,
@@ -799,6 +785,17 @@ decode_reloc(Sym *s, int32 off)
return nil;
}
+static Sym*
+decode_reloc_sym(Sym *s, int32 off)
+{
+ Reloc *r;
+
+ r = decode_reloc(s,off);
+ if (r == nil)
+ return nil;
+ return r->sym;
+}
+
static uvlong
decode_inuxi(uchar* p, int sz)
{
@@ -852,7 +849,7 @@ decodetype_size(Sym *s)
static Sym*
decodetype_arrayelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
static vlong
@@ -865,26 +862,26 @@ decodetype_arraylen(Sym *s)
static Sym*
decodetype_ptrelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
// Type.MapType.key, elem
static Sym*
decodetype_mapkey(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
static Sym*
decodetype_mapvalue(Sym *s)
{
- return decode_reloc(s, 6*PtrSize + 8)->sym; // 0x20 / 0x38
+ return decode_reloc_sym(s, 6*PtrSize + 8); // 0x20 / 0x38
}
// Type.ChanType.elem
static Sym*
decodetype_chanelem(Sym *s)
{
- return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+ return decode_reloc_sym(s, 5*PtrSize + 8); // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
@@ -913,7 +910,9 @@ decodetype_funcintype(Sym *s, int i)
Reloc *r;
r = decode_reloc(s, 6*PtrSize + 8);
- return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
static Sym*
@@ -922,7 +921,9 @@ decodetype_funcouttype(Sym *s, int i)
Reloc *r;
r = decode_reloc(s, 7*PtrSize + 16);
- return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+ if (r == nil)
+ return nil;
+ return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
// Type.StructType.fields.Slice::len
@@ -936,21 +937,20 @@ decodetype_structfieldcount(Sym *s)
static char*
decodetype_structfieldname(Sym *s, int i)
{
- Reloc* r;
-
- r = decode_reloc(s, 6*PtrSize + 0x10 + i*5*PtrSize); // go.string."foo" 0x28 / 0x40
- if (r == nil) // embedded structs have a nil name.
+ // go.string."foo" 0x28 / 0x40
+ s = decode_reloc_sym(s, 6*PtrSize + 0x10 + i*5*PtrSize);
+ if (s == nil) // embedded structs have a nil name.
return nil;
- r = decode_reloc(r->sym, 0); // string."foo"
- if (r == nil) // shouldn't happen.
+ s = decode_reloc_sym(s, 0); // string."foo"
+ if (s == nil) // shouldn't happen.
return nil;
- return (char*)r->sym->p; // the c-string
+ return (char*)s->p; // the c-string
}
static Sym*
decodetype_structfieldtype(Sym *s, int i)
{
- return decode_reloc(s, 8*PtrSize + 0x10 + i*5*PtrSize)->sym; // 0x30 / 0x50
+ return decode_reloc_sym(s, 8*PtrSize + 0x10 + i*5*PtrSize); // 0x30 / 0x50
}
static vlong
@@ -977,6 +977,20 @@ enum {
static DWDie* defptrto(DWDie *dwtype); // below
+// Lookup predefined types
+static Sym*
+lookup_or_diag(char *n)
+{
+ Sym *s;
+
+ s = lookup(n, 0);
+ if (s->size == 0) {
+ diag("dwarf: missing type: %s", n);
+ errorexit();
+ }
+ return s;
+}
+
// Define gotype, for composite ones recurse into constituents.
static DWDie*
defgotype(Sym *gotype)
@@ -995,7 +1009,7 @@ defgotype(Sym *gotype)
diag("Type name doesn't start with \".type\": %s", gotype->name);
return find_or_diag(&dwtypes, "<unspecified>");
}
- name = gotype->name + 5; // Altenatively decode from Type.string
+ name = gotype->name + 5; // could also decode from Type.string
die = find(&dwtypes, name);
if (die != nil)
@@ -1049,7 +1063,6 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
- case KindFloat:
case KindFloat32:
case KindFloat64:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
@@ -1057,7 +1070,6 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
break;
- case KindComplex:
case KindComplex64:
case KindComplex128:
die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
@@ -1107,9 +1119,9 @@ defgotype(Sym *gotype)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
nfields = decodetype_ifacemethodcount(gotype);
if (nfields == 0)
- s = lookup("type.runtime.eface", 0);
+ s = lookup_or_diag("type.runtime.eface");
else
- s = lookup("type.runtime.iface", 0);
+ s = lookup_or_diag("type.runtime.iface");
newrefattr(die, DW_AT_type, defgotype(s));
break;
@@ -1226,7 +1238,7 @@ synthesizestringtypes(DWDie* die)
{
DWDie *prototype;
- prototype = defgotype(lookup("type.runtime.string_", 0));
+ prototype = defgotype(lookup_or_diag("type.runtime._string"));
if (prototype == nil)
return;
@@ -1242,7 +1254,7 @@ synthesizeslicetypes(DWDie *die)
{
DWDie *prototype, *elem;
- prototype = defgotype(lookup("type.runtime.slice",0));
+ prototype = defgotype(lookup_or_diag("type.runtime.slice"));
if (prototype == nil)
return;
@@ -1281,22 +1293,22 @@ synthesizemaptypes(DWDie *die)
{
DWDie *hash, *hash_subtable, *hash_entry,
- *dwh, *dwhs, *dwhe, *keytype, *valtype, *fld;
+ *dwh, *dwhs, *dwhe, *dwhash, *keytype, *valtype, *fld;
int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
DWAttr *a;
- hash = defgotype(lookup("type.runtime.hash",0));
- hash_subtable = defgotype(lookup("type.runtime.hash_subtable",0));
- hash_entry = defgotype(lookup("type.runtime.hash_entry",0));
+ hash = defgotype(lookup_or_diag("type.runtime.hmap"));
+ hash_subtable = defgotype(lookup_or_diag("type.runtime.hash_subtable"));
+ hash_entry = defgotype(lookup_or_diag("type.runtime.hash_entry"));
if (hash == nil || hash_subtable == nil || hash_entry == nil)
return;
- dwh = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
- if (dwh == nil)
+ dwhash = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
+ if (dwhash == nil)
return;
- hashsize = getattr(dwh, DW_AT_byte_size)->value;
+ hashsize = getattr(dwhash, DW_AT_byte_size)->value;
for (; die != nil; die = die->link) {
if (die->abbrev != DW_ABRV_MAPTYPE)
@@ -1328,13 +1340,19 @@ synthesizemaptypes(DWDie *die)
mkinternaltypename("hash_entry",
getattr(keytype, DW_AT_name)->data,
getattr(valtype, DW_AT_name)->data));
- copychildren(dwhe, hash_entry);
- substitutetype(dwhe, "key", keytype);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "hash");
+ newrefattr(fld, DW_AT_type, dwhash);
+ newmemberoffsetattr(fld, 0);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "key");
+ newrefattr(fld, DW_AT_type, keytype);
+ newmemberoffsetattr(fld, hashsize);
+
+ fld = newdie(dwhe, DW_ABRV_STRUCTFIELD, "val");
if (valsize > MaxValsize)
valtype = defptrto(valtype);
- substitutetype(dwhe, "val", valtype);
- fld = find_or_diag(dwhe, "val");
- delattr(fld, DW_AT_data_member_location);
+ newrefattr(fld, DW_AT_type, valtype);
newmemberoffsetattr(fld, hashsize + datavo);
newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
@@ -1371,10 +1389,10 @@ synthesizechantypes(DWDie *die)
DWAttr *a;
int elemsize, linksize, sudogsize;
- sudog = defgotype(lookup("type.runtime.sudoG",0));
- waitq = defgotype(lookup("type.runtime.waitQ",0));
- link = defgotype(lookup("type.runtime.link",0));
- hchan = defgotype(lookup("type.runtime.hChan",0));
+ sudog = defgotype(lookup_or_diag("type.runtime.sudog"));
+ waitq = defgotype(lookup_or_diag("type.runtime.waitq"));
+ link = defgotype(lookup_or_diag("type.runtime.link"));
+ hchan = defgotype(lookup_or_diag("type.runtime.hchan"));
if (sudog == nil || waitq == nil || link == nil || hchan == nil)
return;
@@ -2281,6 +2299,13 @@ writegdbscript(void)
return sectionstart;
}
+static void
+align(vlong size)
+{
+ if((thechar == '6' || thechar == '8') && HEADTYPE == 10) // Only Windows PE need section align.
+ strnput("", rnd(size, PEFILEALIGN) - size);
+}
+
/*
* This is the main entry point for generating dwarf. After emitting
* the mandatory debug_abbrev section, it calls writelines() to set up
@@ -2313,15 +2338,18 @@ dwarfemitdebugsections(void)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
// Needed by the prettyprinter code for interface inspection.
- defgotype(lookup("type.runtime.commonType",0));
- defgotype(lookup("type.runtime.InterfaceType",0));
- defgotype(lookup("type.runtime.itab",0));
+ defgotype(lookup_or_diag("type.runtime.commonType"));
+ defgotype(lookup_or_diag("type.runtime.InterfaceType"));
+ defgotype(lookup_or_diag("type.runtime.itab"));
genasmsym(defdwsymb);
writeabbrev();
+ align(abbrevsize);
writelines();
+ align(linesize);
writeframes();
+ align(framesize);
synthesizestringtypes(dwtypes.child);
synthesizeslicetypes(dwtypes.child);
@@ -2354,16 +2382,23 @@ dwarfemitdebugsections(void)
}
}
infosize = infoe - infoo;
+ align(infosize);
pubnameso = writepub(ispubname);
+ pubnamessize = cpos() - pubnameso;
+ align(pubnamessize);
+
pubtypeso = writepub(ispubtype);
+ pubtypessize = cpos() - pubtypeso;
+ align(pubtypessize);
+
arangeso = writearanges();
- gdbscripto = writegdbscript();
+ arangessize = cpos() - arangeso;
+ align(arangessize);
- pubnamessize = pubtypeso - pubnameso;
- pubtypessize = arangeso - pubtypeso;
- arangessize = gdbscripto - arangeso;
+ gdbscripto = writegdbscript();
gdbscriptsize = cpos() - gdbscripto;
+ align(gdbscriptsize);
}
/*
@@ -2545,3 +2580,24 @@ dwarfaddmachoheaders(void)
ms->filesize += msect->size;
}
}
+
+/*
+ * Windows PE
+ */
+void
+dwarfaddpeheaders(void)
+{
+ dwarfemitdebugsections();
+ newPEDWARFSection(".debug_abbrev", abbrevsize);
+ newPEDWARFSection(".debug_line", linesize);
+ newPEDWARFSection(".debug_frame", framesize);
+ newPEDWARFSection(".debug_info", infosize);
+ if (pubnamessize > 0)
+ newPEDWARFSection(".debug_pubnames", pubnamessize);
+ if (pubtypessize > 0)
+ newPEDWARFSection(".debug_pubtypes", pubtypessize);
+ if (arangessize > 0)
+ newPEDWARFSection(".debug_aranges", arangessize);
+ if (gdbscriptsize > 0)
+ newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
index 7881213c2..f0df2f9b1 100644
--- a/src/cmd/ld/dwarf.h
+++ b/src/cmd/ld/dwarf.h
@@ -27,3 +27,4 @@ void dwarfaddshstrings(Sym *shstrtab);
*/
void dwarfaddelfheaders(void);
void dwarfaddmachoheaders(void);
+void dwarfaddpeheaders(void);
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
new file mode 100644
index 000000000..d8b0a6fc2
--- /dev/null
+++ b/src/cmd/ld/ldpe.c
@@ -0,0 +1,406 @@
+// Copyright 2010 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.
+
+#include "l.h"
+#include "lib.h"
+#include "../ld/pe.h"
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+
+#define IMAGE_SYM_UNDEFINED 0
+#define IMAGE_SYM_ABSOLUTE (-1)
+#define IMAGE_SYM_DEBUG (-2)
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+#define IMAGE_SYM_TYPE_PCODE 32768
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 0x10
+#define IMAGE_SYM_DTYPE_FUNCTION 0x20
+#define IMAGE_SYM_DTYPE_ARRAY 0x30
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (-1)
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_SYM_CLASS_CLR_TOKEN 107
+
+#define IMAGE_REL_I386_ABSOLUTE 0x0000
+#define IMAGE_REL_I386_DIR16 0x0001
+#define IMAGE_REL_I386_REL16 0x0002
+#define IMAGE_REL_I386_DIR32 0x0006
+#define IMAGE_REL_I386_DIR32NB 0x0007
+#define IMAGE_REL_I386_SEG12 0x0009
+#define IMAGE_REL_I386_SECTION 0x000A
+#define IMAGE_REL_I386_SECREL 0x000B
+#define IMAGE_REL_I386_TOKEN 0x000C
+#define IMAGE_REL_I386_SECREL7 0x000D
+#define IMAGE_REL_I386_REL32 0x0014
+
+typedef struct PeSym PeSym;
+typedef struct PeSect PeSect;
+typedef struct PeObj PeObj;
+
+struct PeSym {
+ char* name;
+ uint32 value;
+ uint16 sectnum;
+ uint16 type;
+ uint8 sclass;
+ uint8 aux;
+ Sym* sym;
+};
+
+struct PeSect {
+ char* name;
+ uchar* base;
+ uint64 size;
+ Sym* sym;
+ IMAGE_SECTION_HEADER sh;
+};
+
+struct PeObj {
+ Biobuf *f;
+ char *name;
+ uint32 base;
+
+ PeSect *sect;
+ uint nsect;
+ PeSym *pesym;
+ uint npesym;
+
+ IMAGE_FILE_HEADER fh;
+ char* snames;
+};
+
+static int map(PeObj *obj, PeSect *sect);
+static int readsym(PeObj *obj, int i, PeSym **sym);
+
+void
+ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ char *name;
+ int32 base;
+ int i, j, l, numaux;
+ PeObj *obj;
+ PeSect *sect, *rsect;
+ IMAGE_SECTION_HEADER sh;
+ uchar symbuf[18];
+ Sym *s;
+ Reloc *r, *rp;
+ PeSym *sym;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
+
+ version++;
+ base = Boffset(f);
+
+ obj = mal(sizeof *obj);
+ obj->f = f;
+ obj->base = base;
+ obj->name = pn;
+ // read header
+ if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
+ goto bad;
+ // load section list
+ obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
+ obj->nsect = obj->fh.NumberOfSections;
+ for(i=0; i < obj->fh.NumberOfSections; i++) {
+ if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
+ 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
+ }
+ // load string table
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, &l, sizeof l) != sizeof l)
+ goto bad;
+ obj->snames = mal(l);
+ Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
+ if(Bread(f, obj->snames, l) != l)
+ goto bad;
+ // read symbols
+ obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
+ obj->npesym = obj->fh.NumberOfSymbols;
+ Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
+ for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
+ Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
+ if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
+ goto bad;
+
+ if((symbuf[0] == 0) && (symbuf[1] == 0) &&
+ (symbuf[2] == 0) && (symbuf[3] == 0)) {
+ l = le32(&symbuf[4]);
+ obj->pesym[i].name = (char*)&obj->snames[l];
+ } else { // sym name length <= 8
+ obj->pesym[i].name = mal(9);
+ strncpy(obj->pesym[i].name, (char*)symbuf, 8);
+ obj->pesym[i].name[8] = 0;
+ }
+ obj->pesym[i].value = le32(&symbuf[8]);
+ obj->pesym[i].sectnum = le16(&symbuf[12]);
+ obj->pesym[i].sclass = symbuf[16];
+ obj->pesym[i].aux = symbuf[17];
+ obj->pesym[i].type = le16(&symbuf[14]);
+ numaux = obj->pesym[i].aux;
+ if (numaux < 0)
+ numaux = 0;
+ }
+ // create symbols for mapped sections
+ for(i=0; i<obj->nsect; i++) {
+ sect = &obj->sect[i];
+ if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ if(map(obj, sect) < 0)
+ goto bad;
+
+ name = smprint("%s(%s)", pn, sect->name);
+ s = lookup(name, version);
+ free(name);
+ switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
+ s->type = SRODATA;
+ break;
+ case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
+ case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
+ s->type = SDATA;
+ break;
+ case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
+ s->type = STEXT;
+ break;
+ default:
+ werrstr("unexpected flags for PE section %s", sect->name);
+ goto bad;
+ }
+ s->p = sect->base;
+ s->np = sect->size;
+ s->size = sect->size;
+ if(s->type == STEXT) {
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ }
+ sect->sym = s;
+ }
+
+ // load relocations
+ for(i=0; i<obj->nsect; i++) {
+ rsect = &obj->sect[i];
+ if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
+ continue;
+ if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+ continue;
+ r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
+ Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
+ for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
+ rp = &r[j];
+ if(Bread(f, symbuf, 10) != 10)
+ goto bad;
+
+ uint32 rva, symindex;
+ uint16 type;
+ rva = le32(&symbuf[0]);
+ symindex = le32(&symbuf[4]);
+ type = le16(&symbuf[8]);
+ if(readsym(obj, symindex, &sym) < 0)
+ goto bad;
+ if(sym->sym == nil) {
+ werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
+ goto bad;
+ }
+ rp->sym = sym->sym;
+ rp->siz = 4;
+ rp->off = rva;
+ switch(type) {
+ default:
+ diag("%s: unknown relocation type %d;", pn, type);
+ case IMAGE_REL_I386_REL32:
+ rp->type = D_PCREL;
+ rp->add = 0;
+ break;
+ case IMAGE_REL_I386_DIR32:
+ rp->type = D_ADDR;
+ // load addend from image
+ rp->add = le32(rsect->base+rp->off);
+ break;
+ }
+ }
+ qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
+
+ s = rsect->sym;
+ s->r = r;
+ s->nr = rsect->sh.NumberOfRelocations;
+ }
+
+ // enter sub-symbols into symbol table.
+ // frist 2 entry is file name.
+ for(i=2; i<obj->npesym; i++) {
+ if(obj->pesym[i].name == 0)
+ continue;
+ if(obj->pesym[i].name[0] == '.') //skip section
+ continue;
+ if(obj->pesym[i].sectnum > 0) {
+ sect = &obj->sect[obj->pesym[i].sectnum-1];
+ if(sect->sym == 0)
+ continue;
+ }
+ if(readsym(obj, i, &sym) < 0)
+ goto bad;
+
+ s = sym->sym;
+ if(sym->sectnum == 0) {// extern
+ if(s->type == SDYNIMPORT)
+ s->plt = -2; // flag for dynimport in PE object files.
+ continue;
+ } else if (sym->sectnum > 0) {
+ sect = &obj->sect[sym->sectnum-1];
+ if(sect->sym == 0)
+ diag("%s: %s sym == 0!", pn, s->name);
+ } else {
+ diag("%s: %s sectnum <0!", pn, s->name, sym->sectnum);
+ }
+
+ s->sub = sect->sym->sub;
+ sect->sym->sub = s;
+ s->type = sect->sym->type | SSUB;
+ s->value = sym->value;
+ s->size = 4;
+ s->outer = sect->sym;
+ if(sect->sym->type == STEXT) {
+ Prog *p;
+
+ if(s->text != P)
+ diag("%s: duplicate definition of %s", pn, s->name);
+ // build a TEXT instruction with a unique pc
+ // just to make the rest of the linker happy.
+ p = prg();
+ p->as = ATEXT;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->textflag = 7;
+ p->to.type = D_CONST;
+ p->link = nil;
+ p->pc = pc++;
+ s->text = p;
+
+ etextp->next = s;
+ etextp = s;
+ }
+ }
+
+ return;
+bad:
+ diag("%s: malformed pe file: %r", pn);
+}
+
+static int
+map(PeObj *obj, PeSect *sect)
+{
+ if(sect->base != nil)
+ return 0;
+
+ sect->base = mal(sect->sh.SizeOfRawData);
+ werrstr("short read");
+ if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 ||
+ Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
+ return -1;
+
+ return 0;
+}
+
+static int
+readsym(PeObj *obj, int i, PeSym **y)
+{
+ Sym *s;
+ PeSym *sym;
+ char *name, *p;
+
+ if(i >= obj->npesym || i < 0) {
+ werrstr("invalid pe symbol index");
+ return -1;
+ }
+
+ sym = &obj->pesym[i];
+ *y = sym;
+ s = nil;
+
+ name = sym->name;
+ if(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0) // section
+ name = obj->sect[sym->sectnum-1].sym->name;
+ if(strncmp(sym->name, "__imp__", 6) == 0)
+ name = &sym->name[7]; // __imp__Name => Name
+ else if(sym->name[0] == '_')
+ name = &sym->name[1]; // _Name => Name
+ // remove last @XXX
+ p = strchr(name, '@');
+ if(p)
+ *p = 0;
+
+ switch(sym->type) {
+ default:
+ werrstr("%s: invalid symbol type %d", sym->name, sym->type);
+ return -1;
+ case IMAGE_SYM_DTYPE_FUNCTION:
+ case IMAGE_SYM_DTYPE_NULL:
+ switch(sym->sclass) {
+ case IMAGE_SYM_CLASS_EXTERNAL: //global
+ s = lookup(name, 0);
+ break;
+ case IMAGE_SYM_CLASS_NULL:
+ case IMAGE_SYM_CLASS_STATIC:
+ s = lookup(name, version);
+ break;
+ default:
+ werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
+ return -1;
+ }
+ break;
+ }
+
+ if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
+ s->type = SXREF;
+ sym->sym = s;
+
+ return 0;
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index ae77247c3..b1a62f25e 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -406,6 +406,10 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
ldmacho(f, pkg, len, pn);
return;
}
+ if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
+ ldpe(f, pkg, len, pn);
+ return;
+ }
/* check the header */
line = Brdline(f, '\n');
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index bcf297116..4ac5d37f9 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -130,6 +130,7 @@ void ldobj1(Biobuf *f, char*, int64 len, char *pn);
void ldobj(Biobuf*, char*, int64, char*, int);
void ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*);
+void ldpe(Biobuf*, char*, int64, char*);
void ldpkg(Biobuf*, char*, int64, char*, int);
void mark(Sym *s);
void mkfwd(void);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index 82c6941f2..2c34daab4 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -10,6 +10,7 @@
#include "l.h"
#include "../ld/lib.h"
#include "../ld/pe.h"
+#include "../ld/dwarf.h"
// DOS stub that prints out
// "This program cannot be run in DOS mode."
@@ -33,6 +34,9 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+static char symnames[256];
+static int nextsymoff;
+
int32 PESECTHEADR;
int32 PEFILEHEADR;
@@ -43,26 +47,33 @@ static int nextfileoff;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
+static PE64_IMAGE_OPTIONAL_HEADER oh64;
static IMAGE_SECTION_HEADER sh[16];
+static IMAGE_DATA_DIRECTORY* dd;
+
+#define set(n, v) (pe64 ? (oh64.n = v) : (oh.n = v))
+#define put(v) (pe64 ? vputl(v) : lputl(v))
typedef struct Imp Imp;
struct Imp {
Sym* s;
- long va;
- long vb;
+ uvlong off;
Imp* next;
};
typedef struct Dll Dll;
struct Dll {
char* name;
- int count;
+ uvlong nameoff;
+ uvlong thunkoff;
Imp* ms;
Dll* next;
};
static Dll* dr;
-static int ndll, nimp, nsize;
+
+static Sym *dexport[1024];
+static int nexport;
static IMAGE_SECTION_HEADER*
addpesection(char *name, int sectsize, int filesize, Segment *s)
@@ -99,17 +110,23 @@ addpesection(char *name, int sectsize, int filesize, Segment *s)
void
peinit(void)
{
+ int32 l;
+
switch(thechar) {
// 64-bit architectures
case '6':
pe64 = 1;
+ l = sizeof(oh64);
+ dd = oh64.DataDirectory;
break;
// 32-bit architectures
default:
+ l = sizeof(oh);
+ dd = oh.DataDirectory;
break;
}
-
- PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN);
+
+ PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
nextsectoff = PESECTHEADR;
nextfileoff = PEFILEHEADR;
@@ -118,27 +135,34 @@ peinit(void)
static void
pewrite(void)
{
- int i, j;
-
seek(cout, 0, 0);
ewrite(cout, dosstub, sizeof dosstub);
strnput("PE", 4);
-
- for (i=0; i<sizeof(fh); i++)
- cput(((char*)&fh)[i]);
- for (i=0; i<sizeof(oh); i++)
- cput(((char*)&oh)[i]);
- for (i=0; i<nsect; i++)
- for (j=0; j<sizeof(sh[i]); j++)
- cput(((char*)&sh[i])[j]);
+ cflush();
+ // TODO: This code should not assume that the
+ // memory representation is little-endian or
+ // that the structs are packed identically to
+ // their file representation.
+ ewrite(cout, &fh, sizeof fh);
+ if(pe64)
+ ewrite(cout, &oh64, sizeof oh64);
+ else
+ ewrite(cout, &oh, sizeof oh);
+ ewrite(cout, &sh, nsect * sizeof sh[0]);
}
static void
strput(char *s)
{
- while(*s)
+ int n;
+
+ for(n=0; *s; n++)
cput(*s++);
cput('\0');
+ n++;
+ // string must be padded to even size
+ if(n%2)
+ cput('\0');
}
static Dll*
@@ -146,50 +170,33 @@ initdynimport(void)
{
Imp *m;
Dll *d;
- Sym *s;
+ Sym *s, *dynamic;
int i;
- Sym *dynamic;
dr = nil;
- ndll = 0;
- nimp = 0;
- nsize = 0;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->hash) {
- if(!s->reachable || !s->dynimpname)
+ if(!s->reachable || !s->dynimpname || s->dynexport)
continue;
- nimp++;
for(d = dr; d != nil; d = d->next) {
if(strcmp(d->name,s->dynimplib) == 0) {
m = mal(sizeof *m);
- m->s = s;
- m->next = d->ms;
- d->ms = m;
- d->count++;
- nsize += strlen(s->dynimpname)+2+1;
break;
}
}
if(d == nil) {
d = mal(sizeof *d);
d->name = s->dynimplib;
- d->count = 1;
d->next = dr;
dr = d;
m = mal(sizeof *m);
- m->s = s;
- m->next = 0;
- d->ms = m;
- ndll++;
- nsize += strlen(s->dynimpname)+2+1;
- nsize += strlen(s->dynimplib)+1;
}
+ m->s = s;
+ m->next = d->ms;
+ d->ms = m;
}
- nsize += 20*ndll + 20;
- nsize += 4*nimp + 4*ndll;
-
dynamic = lookup(".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
@@ -199,9 +206,9 @@ initdynimport(void)
m->s->sub = dynamic->sub;
dynamic->sub = m->s;
m->s->value = dynamic->size;
- dynamic->size += 4;
+ dynamic->size += PtrSize;
}
- dynamic->size += 4;
+ dynamic->size += PtrSize;
}
return dr;
@@ -211,90 +218,245 @@ static void
addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
{
IMAGE_SECTION_HEADER *isect;
- uint32 va;
- int noff, aoff, o, last_fn, last_name_off, iat_off;
+ uvlong n, oftbase, ftbase;
Imp *m;
Dll *d;
Sym* dynamic;
- isect = addpesection(".idata", nsize, nsize, 0);
+ dynamic = lookup(".windynamic", 0);
+
+ // skip import descriptor table (will write it later)
+ n = 0;
+ for(d = dr; d != nil; d = d->next)
+ n++;
+ seek(cout, fileoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1), 0);
+
+ // write dll names
+ for(d = dr; d != nil; d = d->next) {
+ d->nameoff = cpos() - fileoff;
+ strput(d->name);
+ }
+
+ // write function names
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ m->off = nextsectoff + cpos() - fileoff;
+ wputl(0); // hint
+ strput(m->s->dynimpname);
+ }
+ }
+
+ // write OriginalFirstThunks
+ oftbase = cpos() - fileoff;
+ n = cpos();
+ for(d = dr; d != nil; d = d->next) {
+ d->thunkoff = cpos() - n;
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+
+ // add pe section and pad it at the end
+ n = cpos() - fileoff;
+ isect = addpesection(".idata", n, n, 0);
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- va = isect->VirtualAddress;
- oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
- oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
+ strnput("", isect->SizeOfRawData - n);
+ cflush();
+ // write FirstThunks (allocated in .data section)
+ ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
+ seek(cout, datsect->PointerToRawData + ftbase, 0);
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next)
+ put(m->off);
+ put(0);
+ }
+ cflush();
+
+ // finally write import descriptor table
seek(cout, fileoff, 0);
-
- dynamic = lookup(".windynamic", 0);
- iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data
- oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off;
- oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
-
- noff = va + 20*ndll + 20;
- aoff = noff + 4*nimp + 4*ndll;
- last_fn = 0;
- last_name_off = aoff;
for(d = dr; d != nil; d = d->next) {
- lputl(noff);
+ lputl(isect->VirtualAddress + oftbase + d->thunkoff);
lputl(0);
lputl(0);
- lputl(last_name_off);
- lputl(iat_off);
- last_fn = d->count;
- noff += 4*last_fn + 4;
- aoff += 4*last_fn + 4;
- iat_off += 4*last_fn + 4;
- last_name_off += strlen(d->name)+1;
+ lputl(isect->VirtualAddress + d->nameoff);
+ lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
}
lputl(0); //end
lputl(0);
lputl(0);
lputl(0);
lputl(0);
+ cflush();
- // put OriginalFirstThunk
- o = last_name_off;
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next) {
- lputl(o);
- o += 2 + strlen(m->s->dynimpname) + 1;
- }
- lputl(0);
- }
- // put names
- for(d = dr; d != nil; d = d->next) {
- strput(d->name);
- }
- // put hint+name
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next) {
- wputl(0);
- strput(m->s->dynimpname);
+ // update data directory
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
+ dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
+
+ seek(cout, 0, 2);
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+ Sym *s1, *s2;
+
+ s1 = *(Sym**)p1;
+ s2 = *(Sym**)p2;
+ return strcmp(s1->dynimpname, s2->dynimpname);
+}
+
+static void
+initdynexport(void)
+{
+ int i;
+ Sym *s;
+
+ nexport = 0;
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->hash) {
+ if(!s->reachable || !s->dynimpname || !s->dynexport)
+ continue;
+ if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
+ diag("pe dynexport table is full");
+ errorexit();
}
+
+ dexport[nexport] = s;
+ nexport++;
}
- strnput("", isect->SizeOfRawData - nsize);
- cflush();
+ qsort(dexport, nexport, sizeof dexport[0], scmp);
+}
- // put FirstThunk
- o = last_name_off;
- seek(cout, datsect->PointerToRawData + dynamic->value - PEBASE - datsect->VirtualAddress, 0);
- for(d = dr; d != nil; d = d->next) {
- for(m = d->ms; m != nil; m = m->next) {
- lputl(o);
- o += 2 + strlen(m->s->dynimpname) + 1;
- }
- lputl(0);
+void
+addexports(vlong fileoff)
+{
+ IMAGE_SECTION_HEADER *sect;
+ IMAGE_EXPORT_DIRECTORY e;
+ int size, i, va, va_name, va_addr, va_na, v;
+
+ size = sizeof e + 10*nexport + strlen(outfile) + 1;
+ for(i=0; i<nexport; i++)
+ size += strlen(dexport[i]->dynimpname) + 1;
+
+ if (nexport == 0)
+ return;
+
+ sect = addpesection(".edata", size, size, 0);
+ sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
+ va = sect->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
+ dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
+
+ seek(cout, fileoff, 0);
+ va_name = va + sizeof e + nexport*4;
+ va_addr = va + sizeof e;
+ va_na = va + sizeof e + nexport*8;
+
+ e.Characteristics = 0;
+ e.MajorVersion = 0;
+ e.MinorVersion = 0;
+ e.NumberOfFunctions = nexport;
+ e.NumberOfNames = nexport;
+ e.Name = va + sizeof e + nexport*10; // Program names.
+ e.Base = 1;
+ e.AddressOfFunctions = va_addr;
+ e.AddressOfNames = va_name;
+ e.AddressOfNameOrdinals = va_na;
+ // put IMAGE_EXPORT_DIRECTORY
+ for (i=0; i<sizeof(e); i++)
+ cput(((char*)&e)[i]);
+ // put EXPORT Address Table
+ for(i=0; i<nexport; i++)
+ lputl(dexport[i]->value - PEBASE);
+ // put EXPORT Name Pointer Table
+ v = e.Name + strlen(outfile)+1;
+ for(i=0; i<nexport; i++) {
+ lputl(v);
+ v += strlen(dexport[i]->dynimpname)+1;
}
+ // put EXPORT Ordinal Table
+ for(i=0; i<nexport; i++)
+ wputl(i);
+ // put Names
+ strnput(outfile, strlen(outfile)+1);
+ for(i=0; i<nexport; i++)
+ strnput(dexport[i]->dynimpname, strlen(dexport[i]->dynimpname)+1);
+ strnput("", sect->SizeOfRawData - size);
cflush();
+
seek(cout, 0, 2);
}
void
dope(void)
{
+ Sym *rel;
+
+ /* relocation table */
+ rel = lookup(".rel", 0);
+ rel->reachable = 1;
+ rel->type = SELFDATA;
+
initdynimport();
+ initdynexport();
+}
+
+/*
+ * For more than 8 characters section names, name contains a slash (/) that is
+ * followed by an ASCII representation of a decimal number that is an offset into
+ * the string table.
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+IMAGE_SECTION_HEADER*
+newPEDWARFSection(char *name, vlong size)
+{
+ IMAGE_SECTION_HEADER *h;
+ char s[8];
+
+ if(nextsymoff+strlen(name)+1 > sizeof(symnames)) {
+ diag("pe string table is full");
+ errorexit();
+ }
+
+ strcpy(&symnames[nextsymoff], name);
+ sprint(s, "/%d\0", nextsymoff+4);
+ nextsymoff += strlen(name);
+ symnames[nextsymoff] = 0;
+ nextsymoff ++;
+ h = addpesection(s, size, size, 0);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+
+ return h;
+}
+
+static void
+addsymtable(void)
+{
+ IMAGE_SECTION_HEADER *h;
+ int i, size;
+
+ if(nextsymoff == 0)
+ return;
+
+ size = nextsymoff + 4;
+ h = addpesection(".symtab", size, size, 0);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_DISCARDABLE;
+ fh.PointerToSymbolTable = cpos();
+ fh.NumberOfSymbols = 0;
+ // put symbol string table
+ lputl(size);
+ for (i=0; i<nextsymoff; i++)
+ cput(symnames[i]);
+ strnput("", h->SizeOfRawData - size);
+ cflush();
}
void
@@ -324,42 +486,51 @@ asmbpe(void)
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
addimports(nextfileoff, d);
+
+ addexports(nextfileoff);
+
+ if(!debug['s'])
+ dwarfaddpeheaders();
+ addsymtable();
+
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
- fh.SizeOfOptionalHeader = sizeof(oh);
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
- if(thechar == '8')
+ if (pe64) {
+ fh.SizeOfOptionalHeader = sizeof(oh64);
+ set(Magic, 0x20b); // PE32+
+ } else {
+ fh.SizeOfOptionalHeader = sizeof(oh);
fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
-
- oh.Magic = 0x10b; // PE32
- oh.MajorLinkerVersion = 1;
- oh.MinorLinkerVersion = 0;
- oh.SizeOfCode = t->SizeOfRawData;
- oh.SizeOfInitializedData = d->SizeOfRawData;
- oh.SizeOfUninitializedData = 0;
- oh.AddressOfEntryPoint = entryvalue()-PEBASE;
- oh.BaseOfCode = t->VirtualAddress;
- oh.BaseOfData = d->VirtualAddress;
-
- oh.ImageBase = PEBASE;
- oh.SectionAlignment = PESECTALIGN;
- oh.FileAlignment = PEFILEALIGN;
- oh.MajorOperatingSystemVersion = 4;
- oh.MinorOperatingSystemVersion = 0;
- oh.MajorImageVersion = 1;
- oh.MinorImageVersion = 0;
- oh.MajorSubsystemVersion = 4;
- oh.MinorSubsystemVersion = 0;
- oh.SizeOfImage = nextsectoff;
- oh.SizeOfHeaders = PEFILEHEADR;
- oh.Subsystem = 3; // WINDOWS_CUI
- oh.SizeOfStackReserve = 0x00200000;
- oh.SizeOfStackCommit = 0x00001000;
- oh.SizeOfHeapReserve = 0x00100000;
- oh.SizeOfHeapCommit = 0x00001000;
- oh.NumberOfRvaAndSizes = 16;
+ set(Magic, 0x10b); // PE32
+ oh.BaseOfData = d->VirtualAddress;
+ }
+ set(MajorLinkerVersion, 1);
+ set(MinorLinkerVersion, 0);
+ set(SizeOfCode, t->SizeOfRawData);
+ set(SizeOfInitializedData, d->SizeOfRawData);
+ set(SizeOfUninitializedData, 0);
+ set(AddressOfEntryPoint, entryvalue()-PEBASE);
+ set(BaseOfCode, t->VirtualAddress);
+ set(ImageBase, PEBASE);
+ set(SectionAlignment, PESECTALIGN);
+ set(FileAlignment, PEFILEALIGN);
+ set(MajorOperatingSystemVersion, 4);
+ set(MinorOperatingSystemVersion, 0);
+ set(MajorImageVersion, 1);
+ set(MinorImageVersion, 0);
+ set(MajorSubsystemVersion, 4);
+ set(MinorSubsystemVersion, 0);
+ set(SizeOfImage, nextsectoff);
+ set(SizeOfHeaders, PEFILEHEADR);
+ set(Subsystem, 3); // WINDOWS_CUI
+ set(SizeOfStackReserve, 0x00200000);
+ set(SizeOfStackCommit, 0x00001000);
+ set(SizeOfHeapReserve, 0x00100000);
+ set(SizeOfHeapCommit, 0x00001000);
+ set(NumberOfRvaAndSizes, 16);
pewrite();
}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index f8161cc4a..6dbf6a5be 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -72,6 +72,20 @@ typedef struct {
uint32 FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ uint32 Characteristics;
+ uint32 TimeDateStamp;
+ uint16 MajorVersion;
+ uint16 MinorVersion;
+ uint32 Name;
+ uint32 Base;
+ uint32 NumberOfFunctions;
+ uint32 NumberOfNames;
+ uint32 AddressOfFunctions;
+ uint32 AddressOfNames;
+ uint32 AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY;
+
#define PEBASE 0x00400000
// SectionAlignment must be greater than or equal to FileAlignment.
// The default is the page size for the architecture.
@@ -99,6 +113,7 @@ enum {
IMAGE_SCN_MEM_EXECUTE = 0x20000000,
IMAGE_SCN_MEM_READ = 0x40000000,
IMAGE_SCN_MEM_WRITE = 0x80000000,
+ IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
@@ -122,3 +137,38 @@ void peinit(void);
void asmbpe(void);
void dope(void);
+IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
+
+// X64
+typedef struct {
+ uint16 Magic;
+ uint8 MajorLinkerVersion;
+ uint8 MinorLinkerVersion;
+ uint32 SizeOfCode;
+ uint32 SizeOfInitializedData;
+ uint32 SizeOfUninitializedData;
+ uint32 AddressOfEntryPoint;
+ uint32 BaseOfCode;
+ uint64 ImageBase;
+ uint32 SectionAlignment;
+ uint32 FileAlignment;
+ uint16 MajorOperatingSystemVersion;
+ uint16 MinorOperatingSystemVersion;
+ uint16 MajorImageVersion;
+ uint16 MinorImageVersion;
+ uint16 MajorSubsystemVersion;
+ uint16 MinorSubsystemVersion;
+ uint32 Win32VersionValue;
+ uint32 SizeOfImage;
+ uint32 SizeOfHeaders;
+ uint32 CheckSum;
+ uint16 Subsystem;
+ uint16 DllCharacteristics;
+ uint64 SizeOfStackReserve;
+ uint64 SizeOfStackCommit;
+ uint64 SizeOfHeapReserve;
+ uint64 SizeOfHeapCommit;
+ uint32 LoaderFlags;
+ uint32 NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} PE64_IMAGE_OPTIONAL_HEADER;