summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.h5
-rw-r--r--src/cmd/5a/a.y8
-rw-r--r--src/cmd/5a/lex.c10
-rw-r--r--src/cmd/5c/Makefile21
-rw-r--r--src/cmd/5c/list.c16
-rw-r--r--src/cmd/5c/mul.c4
-rw-r--r--src/cmd/5c/peep.c2
-rw-r--r--src/cmd/5c/reg.c10
-rw-r--r--src/cmd/5c/swt.c42
-rw-r--r--src/cmd/5c/txt.c61
-rw-r--r--src/cmd/5g/Makefile25
-rw-r--r--src/cmd/5g/cgen.c232
-rw-r--r--src/cmd/5g/cgen64.c6
-rw-r--r--src/cmd/5g/galign.c1
-rw-r--r--src/cmd/5g/gg.h6
-rw-r--r--src/cmd/5g/ggen.c87
-rw-r--r--src/cmd/5g/gobj.c6
-rw-r--r--src/cmd/5g/gsubr.c221
-rw-r--r--src/cmd/5g/list.c34
-rw-r--r--src/cmd/5g/opt.h2
-rw-r--r--src/cmd/5g/peep.c1511
-rw-r--r--src/cmd/5g/reg.c1329
-rw-r--r--src/cmd/5l/5.out.h8
-rw-r--r--src/cmd/5l/Makefile24
-rw-r--r--src/cmd/5l/asm.c1310
-rw-r--r--src/cmd/5l/doc.go4
-rw-r--r--src/cmd/5l/l.h143
-rw-r--r--src/cmd/5l/list.c146
-rw-r--r--src/cmd/5l/noop.c1371
-rw-r--r--src/cmd/5l/obj.c475
-rw-r--r--src/cmd/5l/optab.c63
-rw-r--r--src/cmd/5l/pass.c803
-rw-r--r--src/cmd/5l/prof.c214
-rw-r--r--src/cmd/5l/softfloat.c113
-rw-r--r--src/cmd/5l/span.c671
-rw-r--r--src/cmd/5l/thumb.c78
-rw-r--r--src/cmd/6a/Makefile23
-rw-r--r--src/cmd/6a/a.h9
-rw-r--r--src/cmd/6a/a.y14
-rw-r--r--src/cmd/6a/lex.c10
-rw-r--r--src/cmd/6c/Makefile21
-rw-r--r--src/cmd/6c/cgen.c10
-rw-r--r--src/cmd/6c/div.c4
-rw-r--r--src/cmd/6c/list.c15
-rw-r--r--src/cmd/6c/mul.c2
-rw-r--r--src/cmd/6c/peep.c2
-rw-r--r--src/cmd/6c/reg.c12
-rw-r--r--src/cmd/6c/sgen.c4
-rw-r--r--src/cmd/6c/swt.c29
-rw-r--r--src/cmd/6c/txt.c23
-rw-r--r--src/cmd/6g/Makefile21
-rw-r--r--src/cmd/6g/cgen.c257
-rw-r--r--src/cmd/6g/galign.c1
-rw-r--r--src/cmd/6g/gg.h2
-rw-r--r--src/cmd/6g/ggen.c85
-rw-r--r--src/cmd/6g/gobj.c4
-rw-r--r--src/cmd/6g/gsubr.c149
-rw-r--r--src/cmd/6g/list.c18
-rw-r--r--src/cmd/6g/reg.c20
-rw-r--r--src/cmd/6l/6.out.h6
-rw-r--r--src/cmd/6l/Makefile26
-rw-r--r--src/cmd/6l/asm.c1389
-rw-r--r--src/cmd/6l/doc.go4
-rw-r--r--src/cmd/6l/l.h140
-rw-r--r--src/cmd/6l/list.c73
-rw-r--r--src/cmd/6l/obj.c549
-rw-r--r--src/cmd/6l/optab.c6
-rw-r--r--src/cmd/6l/pass.c1112
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1282
-rw-r--r--src/cmd/8a/Makefile23
-rw-r--r--src/cmd/8a/a.h9
-rw-r--r--src/cmd/8a/a.y8
-rw-r--r--src/cmd/8a/lex.c10
-rw-r--r--src/cmd/8c/Makefile21
-rw-r--r--src/cmd/8c/cgen64.c4
-rw-r--r--src/cmd/8c/div.c4
-rw-r--r--src/cmd/8c/list.c30
-rw-r--r--src/cmd/8c/mul.c2
-rw-r--r--src/cmd/8c/reg.c10
-rw-r--r--src/cmd/8c/swt.c38
-rw-r--r--src/cmd/8c/txt.c11
-rw-r--r--src/cmd/8g/Makefile21
-rw-r--r--src/cmd/8g/cgen.c69
-rw-r--r--src/cmd/8g/galign.c1
-rw-r--r--src/cmd/8g/ggen.c116
-rw-r--r--src/cmd/8g/gobj.c4
-rw-r--r--src/cmd/8g/gsubr.c14
-rw-r--r--src/cmd/8g/list.c14
-rw-r--r--src/cmd/8g/reg.c22
-rw-r--r--src/cmd/8l/8.out.h8
-rw-r--r--src/cmd/8l/Makefile29
-rw-r--r--src/cmd/8l/asm.c1328
-rw-r--r--src/cmd/8l/doc.go4
-rw-r--r--src/cmd/8l/l.h136
-rw-r--r--src/cmd/8l/list.c87
-rw-r--r--src/cmd/8l/obj.c505
-rw-r--r--src/cmd/8l/optab.c4
-rw-r--r--src/cmd/8l/pass.c1058
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1183
-rw-r--r--src/cmd/cc/Makefile21
-rw-r--r--src/cmd/cc/acid.c12
-rw-r--r--src/cmd/cc/cc.h3
-rw-r--r--src/cmd/cc/com.c6
-rw-r--r--src/cmd/cc/dcl.c39
-rw-r--r--src/cmd/cc/dpchk.c13
-rw-r--r--src/cmd/cc/lex.c10
-rw-r--r--src/cmd/cc/macbody2
-rw-r--r--src/cmd/cc/pgen.c8
-rw-r--r--src/cmd/cc/pickle.c10
-rw-r--r--src/cmd/cc/pswt.c4
-rw-r--r--src/cmd/cc/sub.c8
-rw-r--r--src/cmd/cgo/Makefile2
-rw-r--r--src/cmd/cgo/ast.go465
-rw-r--r--src/cmd/cgo/doc.go25
-rw-r--r--src/cmd/cgo/gcc.go543
-rw-r--r--src/cmd/cgo/main.go256
-rw-r--r--src/cmd/cgo/out.go524
-rw-r--r--src/cmd/cgo/util.go51
-rw-r--r--src/cmd/clean.bash4
-rw-r--r--src/cmd/cov/Makefile22
-rw-r--r--src/cmd/cov/main.c2
-rw-r--r--src/cmd/ebnflint/Makefile4
-rw-r--r--src/cmd/ebnflint/ebnflint.go6
-rw-r--r--src/cmd/gc/Makefile23
-rw-r--r--src/cmd/gc/align.c76
-rw-r--r--src/cmd/gc/builtin.c.boot18
-rw-r--r--src/cmd/gc/closure.c2
-rw-r--r--src/cmd/gc/const.c22
-rw-r--r--src/cmd/gc/dcl.c20
-rw-r--r--src/cmd/gc/doc.go9
-rw-r--r--src/cmd/gc/export.c3
-rw-r--r--src/cmd/gc/gen.c20
-rw-r--r--src/cmd/gc/go.errors9
-rw-r--r--src/cmd/gc/go.h48
-rw-r--r--src/cmd/gc/go.y174
-rw-r--r--src/cmd/gc/lex.c203
-rwxr-xr-xsrc/cmd/gc/mkbuiltin8
-rw-r--r--src/cmd/gc/mparith1.c42
-rw-r--r--src/cmd/gc/mparith2.c8
-rw-r--r--src/cmd/gc/mparith3.c30
-rw-r--r--src/cmd/gc/obj.c107
-rw-r--r--src/cmd/gc/print.c61
-rw-r--r--src/cmd/gc/range.c17
-rw-r--r--src/cmd/gc/reflect.c116
-rw-r--r--src/cmd/gc/runtime.go22
-rw-r--r--src/cmd/gc/select.c13
-rw-r--r--src/cmd/gc/sinit.c62
-rw-r--r--src/cmd/gc/subr.c177
-rw-r--r--src/cmd/gc/typecheck.c490
-rw-r--r--src/cmd/gc/unsafe.c20
-rw-r--r--src/cmd/gc/walk.c405
-rw-r--r--src/cmd/godefs/Makefile14
-rw-r--r--src/cmd/godefs/main.c10
-rw-r--r--src/cmd/godefs/stabs.c13
-rw-r--r--src/cmd/godoc/Makefile5
-rw-r--r--src/cmd/godoc/codewalk.go51
-rw-r--r--src/cmd/godoc/dirtrees.go341
-rw-r--r--src/cmd/godoc/doc.go17
-rw-r--r--src/cmd/godoc/format.go342
-rw-r--r--src/cmd/godoc/godoc.go1031
-rw-r--r--src/cmd/godoc/index.go295
-rw-r--r--src/cmd/godoc/main.go80
-rw-r--r--src/cmd/godoc/mapping.go94
-rwxr-xr-xsrc/cmd/godoc/snippet.go53
-rw-r--r--src/cmd/godoc/spec.go37
-rw-r--r--src/cmd/godoc/utils.go109
-rw-r--r--src/cmd/gofmt/Makefile6
-rw-r--r--src/cmd/gofmt/doc.go4
-rw-r--r--src/cmd/gofmt/gofmt.go25
-rw-r--r--src/cmd/gofmt/rewrite.go61
-rw-r--r--src/cmd/gofmt/simplify.go67
-rwxr-xr-xsrc/cmd/gofmt/test.sh5
-rw-r--r--src/cmd/gofmt/testdata/composites.golden104
-rw-r--r--src/cmd/gofmt/testdata/composites.input104
-rwxr-xr-xsrc/cmd/gofmt/testdata/test.sh65
-rw-r--r--src/cmd/goinstall/Makefile2
-rw-r--r--src/cmd/goinstall/doc.go41
-rw-r--r--src/cmd/goinstall/download.go57
-rw-r--r--src/cmd/goinstall/main.go91
-rw-r--r--src/cmd/goinstall/make.go80
-rw-r--r--src/cmd/goinstall/parse.go77
-rw-r--r--src/cmd/gomake/doc.go36
-rw-r--r--src/cmd/gopack/Makefile13
-rw-r--r--src/cmd/gopack/ar.c33
-rw-r--r--src/cmd/gopack/doc.go2
-rw-r--r--src/cmd/gotest/Makefile16
-rwxr-xr-xsrc/cmd/gotest/gotest73
-rwxr-xr-xsrc/cmd/gotest/gotry167
-rw-r--r--src/cmd/govet/Makefile11
-rw-r--r--src/cmd/govet/doc.go38
-rw-r--r--src/cmd/govet/govet.go325
-rw-r--r--src/cmd/goyacc/Makefile2
-rw-r--r--src/cmd/goyacc/goyacc.go41
-rw-r--r--src/cmd/goyacc/units.y8
-rw-r--r--src/cmd/hgpatch/Makefile2
-rw-r--r--src/cmd/hgpatch/main.go12
-rw-r--r--src/cmd/ld/data.c914
-rw-r--r--src/cmd/ld/dwarf.c2547
-rw-r--r--src/cmd/ld/dwarf.h29
-rw-r--r--src/cmd/ld/dwarf_defs.h503
-rw-r--r--src/cmd/ld/elf.c124
-rw-r--r--src/cmd/ld/elf.h8
-rw-r--r--src/cmd/ld/go.c182
-rw-r--r--src/cmd/ld/ldelf.c816
-rw-r--r--src/cmd/ld/ldmacho.c794
-rw-r--r--src/cmd/ld/lib.c546
-rw-r--r--src/cmd/ld/lib.h97
-rw-r--r--src/cmd/ld/macho.c394
-rw-r--r--src/cmd/ld/macho.h19
-rw-r--r--src/cmd/ld/pe.c307
-rw-r--r--src/cmd/ld/pe.h14
-rw-r--r--src/cmd/ld/symtab.c259
-rwxr-xr-xsrc/cmd/make.bash10
-rw-r--r--src/cmd/nm/Makefile18
-rw-r--r--src/cmd/nm/nm.c17
-rw-r--r--src/cmd/prof/Makefile24
-rwxr-xr-xsrc/cmd/prof/gopprof41
-rw-r--r--src/cmd/prof/main.c37
221 files changed, 22731 insertions, 12800 deletions
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
index f01b017da..f4463c97b 100644
--- a/src/cmd/5a/Makefile
+++ b/src/cmd/5a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5a\
+TARG=5a
HFILES=\
a.h\
@@ -15,26 +15,11 @@ HFILES=\
OFILES=\
y.tab.$O\
lex.$O\
-# ../5l/enam.$O\
+ ../5l/enam.$O\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.5 enam.c 5.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index 6cd5af8c6..bc4f433e1 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/5a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -148,6 +148,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -157,7 +158,7 @@ EXTERN Biobuf obuf;
void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index bb30ac698..b39c916ab 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/5a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -63,7 +63,11 @@
%type <gen> imm ximm name oreg ireg nireg ioreg imsr
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index 2cc0993e4..b36094a78 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/5a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -658,10 +658,10 @@ jackpot:
Bputc(&obuf, a);
Bputc(&obuf, scond);
Bputc(&obuf, reg);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(g1, sf);
zaddr(g2, st);
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
index b534206f3..70b614e8a 100644
--- a/src/cmd/5c/Makefile
+++ b/src/cmd/5c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5c\
+TARG=5c
HFILES=\
gc.h\
@@ -26,18 +26,9 @@ OFILES=\
../5l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
index c792c130d..ab0fae83c 100644
--- a/src/cmd/5c/list.c
+++ b/src/cmd/5c/list.c
@@ -59,7 +59,7 @@ Bconv(Fmt *fp)
if(str[0])
strcat(str, " ");
if(var[i].sym == S) {
- sprint(ss, "$%ld", var[i].offset);
+ sprint(ss, "$%d", var[i].offset);
s = ss;
} else
s = var[i].sym->name;
@@ -204,7 +204,7 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- sprint(str, "%ld(PC)", a->offset-pc);
+ sprint(str, "%d(PC)", a->offset-pc);
break;
case D_FCONST:
@@ -307,7 +307,7 @@ Nconv(Fmt *fp)
a = va_arg(fp->args, Adr*);
s = a->sym;
if(s == S) {
- sprint(str, "%ld", a->offset);
+ sprint(str, "%d", a->offset);
goto out;
}
switch(a->name) {
@@ -316,23 +316,23 @@ Nconv(Fmt *fp)
break;
case D_NONE:
- sprint(str, "%ld", a->offset);
+ sprint(str, "%d", a->offset);
break;
case D_EXTERN:
- sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ sprint(str, "%s+%d(SB)", s->name, a->offset);
break;
case D_STATIC:
- sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ sprint(str, "%s<>+%d(SB)", s->name, a->offset);
break;
case D_AUTO:
- sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ sprint(str, "%s-%d(SP)", s->name, -a->offset);
break;
case D_PARAM:
- sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ sprint(str, "%s+%d(FP)", s->name, a->offset);
break;
}
out:
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
index 121f67d5b..ff50c4845 100644
--- a/src/cmd/5c/mul.c
+++ b/src/cmd/5c/mul.c
@@ -115,7 +115,7 @@ mulcon0(int32 v)
if(docode(hintab[g].hint, m->code, 1, 0))
return m;
- print("multiply table failure %ld\n", v);
+ print("multiply table failure %d\n", v);
m->code[0] = 0;
return 0;
@@ -132,7 +132,7 @@ no:
if(gen1(g)) {
if(docode(hint, m->code, 1, 0))
return m;
- print("multiply table failure %ld\n", v);
+ print("multiply table failure %d\n", v);
break;
}
}
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
index 4959d414d..8945ee732 100644
--- a/src/cmd/5c/peep.c
+++ b/src/cmd/5c/peep.c
@@ -1324,8 +1324,6 @@ predicable(Prog *p)
|| p->as == ASIGNAME
|| p->as == ATEXT
|| p->as == AWORD
- || p->as == ADYNT
- || p->as == AINIT
|| p->as == ABCASE
|| p->as == ACASE)
return 0;
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
index f2d38d519..8c9794418 100644
--- a/src/cmd/5c/reg.c
+++ b/src/cmd/5c/reg.c
@@ -309,7 +309,7 @@ loop2:
if(debug['R'] && debug['v']) {
print("\nprop structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] |
r->refahead.b[z] | r->calahead.b[z] |
@@ -955,7 +955,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -965,21 +965,21 @@ paint1(Reg *r, int bn)
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index cefbf53d9..43eb73c94 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -47,7 +47,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
gopcode(OEQ, nodconst(q->val), n, Z);
patch(p, q->label);
q++;
@@ -60,7 +60,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
i = nc / 2;
r = q+i;
if(debug['W'])
- print("case > %.8lux\n", r->val);
+ print("case > %.8ux\n", r->val);
gopcode(OGT, nodconst(r->val), n, Z);
sp = p;
gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
@@ -68,7 +68,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
swit1(q, i, def, n);
if(debug['W'])
- print("case < %.8lux\n", r->val);
+ print("case < %.8ux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
return;
@@ -81,7 +81,7 @@ direct:
patch(p, def);
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
while(q->val != v) {
nextpc();
p->as = ABCASE;
@@ -227,7 +227,7 @@ mulcon(Node *n, Node *nn)
return 0;
}
if(debug['M'] && debug['v'])
- print("%L multiply: %ld\n", n->lineno, v);
+ print("%L multiply: %d\n", n->lineno, v);
memmove(code, m->code, sizeof(m->code));
code[sizeof(m->code)] = 0;
@@ -606,7 +606,7 @@ zaddr(char *bp, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -620,7 +620,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_LONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -628,10 +630,16 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_LONG)
- w = SZ_LONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else {
+ w = ewidth[v->etype];
+ if(w == 8)
+ w = 4;
+ }
+ if(w < 1 || w > SZ_LONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -641,8 +649,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -661,14 +669,16 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael2);
- o = align(o, t, Ael1);
+ o = align(o, t, Ael2, nil);
+ o = align(o, t, Ael1, nil);
w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
break;
}
o = xround(o, w);
+ if(maxalign != nil && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index 9dac0312f..0f17cea89 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -388,7 +388,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -402,22 +402,22 @@ regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg + SZ_LONG;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -580,7 +580,8 @@ void
gmove(Node *f, Node *t)
{
int ft, tt, a;
- Node nod;
+ Node nod, nod1;
+ Prog *p1;
ft = f->type->etype;
tt = t->type->etype;
@@ -709,21 +710,53 @@ gmove(Node *f, Node *t)
}
break;
case TUINT:
- case TINT:
case TULONG:
+ if(tt == TFLOAT || tt == TDOUBLE) {
+ // ugly and probably longer than necessary,
+ // but vfp has a single instruction for this,
+ // so hopefully it won't last long.
+ //
+ // tmp = f
+ // tmp1 = tmp & 0x80000000
+ // tmp ^= tmp1
+ // t = float(int32(tmp))
+ // if(tmp1)
+ // t += 2147483648.
+ //
+ regalloc(&nod, f, Z);
+ regalloc(&nod1, f, Z);
+ gins(AMOVW, f, &nod);
+ gins(AMOVW, &nod, &nod1);
+ gins(AAND, nodconst(0x80000000), &nod1);
+ gins(AEOR, &nod1, &nod);
+ if(tt == TFLOAT)
+ gins(AMOVWF, &nod, t);
+ else
+ gins(AMOVWD, &nod, t);
+ gins(ACMP, nodconst(0), Z);
+ raddr(&nod1, p);
+ gins(ABEQ, Z, Z);
+ regfree(&nod);
+ regfree(&nod1);
+ p1 = p;
+ regalloc(&nod, t, Z);
+ gins(AMOVF, nodfconst(2147483648.), &nod);
+ gins(AADDF, &nod, t);
+ regfree(&nod);
+ patch(p1, pc);
+ return;
+ }
+ // fall through
+
+ case TINT:
case TLONG:
case TIND:
switch(tt) {
case TDOUBLE:
- case TVLONG:
gins(AMOVWD, f, t);
- if(ft == TULONG) {
- }
return;
case TFLOAT:
gins(AMOVWF, f, t);
- if(ft == TULONG) {
- }
return;
case TINT:
case TUINT:
@@ -741,7 +774,6 @@ gmove(Node *f, Node *t)
case TSHORT:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(AMOVWD, &nod, t);
@@ -771,7 +803,6 @@ gmove(Node *f, Node *t)
case TUSHORT:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWD, &nod, t);
@@ -801,7 +832,6 @@ gmove(Node *f, Node *t)
case TCHAR:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(AMOVWD, &nod, t);
@@ -831,7 +861,6 @@ gmove(Node *f, Node *t)
case TUCHAR:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWD, &nod, t);
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
index 123af19cd..6873fbc68 100644
--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5g
+TARG=5g
HFILES=\
../gc/go.h\
@@ -21,18 +21,15 @@ OFILES=\
ggen.$O\
gsubr.$O\
cgen.$O\
- cgen64.$O
+ cgen64.$O\
+ cplx.$O\
+ reg.$O\
+ peep.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
+include ../../Make.ccmd
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.o $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+%.$O: ../gc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 8072c3ceb..1328f4be6 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -4,33 +4,6 @@
#include "gg.h"
-void
-mgen(Node *n, Node *n1, Node *rg)
-{
- n1->ostk = 0;
- n1->op = OEMPTY;
-
- if(n->addable) {
- *n1 = *n;
- n1->ostk = 0;
- if(n1->op == OREGISTER || n1->op == OINDREG)
- reg[n->val.u.reg]++;
- return;
- }
- if(n->type->width > widthptr)
- tempname(n1, n->type);
- else
- regalloc(n1, n->type, rg);
- cgen(n, n1);
-}
-
-void
-mfree(Node *n)
-{
- if(n->op == OREGISTER)
- regfree(n);
-}
-
/*
* generate:
* res = n;
@@ -55,12 +28,6 @@ cgen(Node *n, Node *res)
if(res == N || res->type == T)
fatal("cgen: res nil");
- // TODO compile complex
- if(n != N && n->type != T && iscomplex[n->type->etype])
- return;
- if(res != N && res->type != T && iscomplex[res->type->etype])
- return;
-
while(n->op == OCONVNOP)
n = n->left;
@@ -80,6 +47,7 @@ cgen(Node *n, Node *res)
goto ret;
}
+
// update addressability for string, slice
// can't do in walk because n->left->addable
// changes if n->left is an escaping local variable.
@@ -96,7 +64,9 @@ cgen(Node *n, Node *res)
// if both are addressable, move
if(n->addable && res->addable) {
- if (is64(n->type) || is64(res->type) || n->op == OREGISTER || res->op == OREGISTER) {
+ if(is64(n->type) || is64(res->type) ||
+ n->op == OREGISTER || res->op == OREGISTER ||
+ iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
gmove(n, res);
} else {
regalloc(&n1, n->type, N);
@@ -126,8 +96,13 @@ cgen(Node *n, Node *res)
return;
}
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ return;
+ }
+
// if n is sudoaddable generate addr and move
- if (!is64(n->type) && !is64(res->type)) {
+ if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
a = optoas(OAS, n->type);
if(sudoaddable(a, n, &addr, &w)) {
if (res->op != OREGISTER) {
@@ -195,8 +170,8 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
case OCMPLX:
- // TODO compile complex
- return;
+ fatal("unexpected complex");
+ break;
// these call bgen to get a bool value
case OOROR:
@@ -269,10 +244,26 @@ cgen(Node *n, Node *res)
cgen(nl, res);
break;
}
-
- mgen(nl, &n1, res);
- gmove(&n1, res);
- mfree(&n1);
+ if(nl->addable && !is64(nl->type)) {
+ regalloc(&n1, nl->type, res);
+ gmove(nl, &n1);
+ } else {
+ if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
+ tempname(&n1, nl->type);
+ else
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ }
+ if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
+ tempname(&n2, n->type);
+ else
+ regalloc(&n2, n->type, N);
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ if(n1.op == OREGISTER)
+ regfree(&n1);
+ if(n2.op == OREGISTER)
+ regfree(&n2);
break;
case ODOT:
@@ -461,6 +452,41 @@ ret:
}
/*
+ * generate array index into res.
+ * n might be any size; res is 32-bit.
+ * returns Prog* to patch to panic call.
+ */
+Prog*
+cgenindex(Node *n, Node *res)
+{
+ Node tmp, lo, hi, zero, n1, n2;
+
+ if(!is64(n->type)) {
+ cgen(n, res);
+ return nil;
+ }
+
+ tempname(&tmp, types[TINT64]);
+ cgen(n, &tmp);
+ split64(&tmp, &lo, &hi);
+ gmove(&lo, res);
+ if(debug['B']) {
+ splitclean();
+ return nil;
+ }
+ regalloc(&n1, types[TINT32], N);
+ regalloc(&n2, types[TINT32], N);
+ nodconst(&zero, types[TINT32], 0);
+ gmove(&hi, &n1);
+ gmove(&zero, &n2);
+ gcmp(ACMP, &n1, &n2);
+ regfree(&n2);
+ regfree(&n1);
+ splitclean();
+ return gbranch(ABNE, T);
+}
+
+/*
* generate:
* res = &n;
*/
@@ -469,10 +495,10 @@ agen(Node *n, Node *res)
{
Node *nl, *nr;
Node n1, n2, n3, n4, n5, tmp;
- Prog *p1;
+ Prog *p1, *p2;
uint32 w;
uint64 v;
- Type *t;
+ int r;
if(debug['g']) {
dump("\nagen-res", res);
@@ -504,7 +530,22 @@ agen(Node *n, Node *res)
break;
case OCALLMETH:
- cgen_callmeth(n, 0);
+ case OCALLFUNC:
+ // Release res so that it is available for cgen_call.
+ // Pick it up again after the call.
+ r = -1;
+ if(n->ullman >= UINF) {
+ if(res->op == OREGISTER || res->op == OINDREG) {
+ r = res->val.u.reg;
+ reg[r]--;
+ }
+ }
+ if(n->op == OCALLMETH)
+ cgen_callmeth(n, 0);
+ else
+ cgen_call(n, 0);
+ if(r >= 0)
+ reg[r]++;
cgen_aret(n, res);
break;
@@ -513,36 +554,36 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
- case OCALLFUNC:
- cgen_call(n, 0);
- cgen_aret(n, res);
- break;
-
case OINDEX:
- // TODO(rsc): uint64 indices
+ p2 = nil; // to be patched to panicindex.
w = n->type->width;
if(nr->addable) {
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
+ if(!isconst(nr, CTINT))
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ if(!isconst(nr, CTINT)) {
+ p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
} else if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
} else {
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ p2 = cgenindex(nr, &tmp);
nr = &tmp;
- agenr(nl, &n3, res);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
@@ -556,9 +597,10 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index");
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
@@ -582,13 +624,6 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
nodconst(&n2, types[tptr], v*w);
@@ -602,19 +637,17 @@ agen(Node *n, Node *res)
break;
}
- // type of the index
- t = types[TUINT32];
- if(issigned[n1.type->etype])
- t = types[TINT32];
-
- regalloc(&n2, t, &n1); // i
+ regalloc(&n2, types[TINT32], &n1); // i
gmove(&n1, &n2);
regfree(&n1);
if(!debug['B'] && !n->etype) {
// check bounds
regalloc(&n4, types[TUINT32], N);
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR)) {
+ nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
+ gmove(&n1, &n4);
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -627,11 +660,18 @@ agen(Node *n, Node *res)
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p2)
+ patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
-
- if(isslice(nl->type)) {
+
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], 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) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -653,10 +693,10 @@ agen(Node *n, Node *res)
else if(w == 8)
gshift(AADD, &n2, SHIFT_LL, 3, &n3);
} else {
- regalloc(&n4, t, N);
- nodconst(&n1, t, w);
+ regalloc(&n4, types[TUINT32], N);
+ nodconst(&n1, types[TUINT32], w);
gmove(&n1, &n4);
- gins(optoas(OMUL, t), &n4, &n2);
+ gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
regfree(&n4);
gmove(&n3, res);
@@ -769,12 +809,8 @@ igen(Node *n, Node *a, Node *res)
void
agenr(Node *n, Node *a, Node *res)
{
- Node n1;
-
- tempname(&n1, types[tptr]);
- agen(n, &n1);
regalloc(a, types[tptr], res);
- gmove(&n1, a);
+ agen(n, a);
}
/*
@@ -796,15 +832,12 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
- // TODO compile complex
- if(nl != N && nl->type != T && iscomplex[nl->type->etype])
- return;
- if(nr != N && nr->type != T && iscomplex[nr->type->etype])
- return;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -925,6 +958,7 @@ bgen(Node *n, int true, Prog *to)
goto ret;
}
a = brcom(a);
+ true = !true;
}
// make simplest on right
@@ -985,6 +1019,11 @@ bgen(Node *n, int true, Prog *to)
break;
}
+ if(iscomplex[nl->type->etype]) {
+ complexbool(a, nl, nr, true, to);
+ break;
+ }
+
if(is64(nr->type)) {
if(!nl->addable) {
tempname(&n1, nl->type);
@@ -1031,7 +1070,16 @@ bgen(Node *n, int true, Prog *to)
cgen(nr, &n2);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
+ if(isfloat[nl->type->etype]) {
+ p1 = gbranch(ABVS, nr->type);
+ patch(gbranch(a, nr->type), to);
+ if(n->op == ONE)
+ patch(p1, to);
+ else
+ patch(p1, pc);
+ } else {
+ patch(gbranch(a, nr->type), to);
+ }
regfree(&n1);
regfree(&n2);
@@ -1088,7 +1136,7 @@ stkof(Node *n)
t = structfirst(&flist, getoutarg(t));
if(t != T)
- return t->width;
+ return t->width + 4; // correct for LR
break;
}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index a22f4a548..716ec5ed5 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -439,12 +439,12 @@ olsh_break:
p3 = gbranch(ABLO, T);
// shift == 32
+ p1 = gins(AMOVW, &bh, &al);
+ p1->scond = C_SCOND_EQ;
if(bh.type->etype == TINT32)
p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &al);
+ p1 = gins(AEOR, &ah, &ah);
p1->scond = C_SCOND_EQ;
p4 = gbranch(ABEQ, T);
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 76affbf00..9c8760aea 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 4;
widthptr = 4;
zprog.link = P;
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index c62efeb6c..603c09fc8 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -33,12 +33,13 @@ struct Addr
struct Prog
{
- short as; // opcode
+ short as; // opcode
uint32 loc; // pc offset in this func
uint32 lineno; // source line that generated this
Addr from; // src address
- Addr to; // dst address
+ Addr to; // dst address
Prog* link; // next instruction in this func
+ void* regp; // points to enclosing Reg struct
char reg; // doubles as width in DATA op
uchar scond;
};
@@ -90,6 +91,7 @@ void ginscall(Node*, int);
* cgen
*/
void agen(Node*, Node*);
+Prog* cgenindex(Node *, Node *);
void igen(Node*, Node*, Node*);
void agenr(Node *n, Node *a, Node *res);
vlong fieldoffset(Type*, Node*);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 3243bb863..42a89415d 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -61,11 +61,14 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+
+ setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
+ ginit();
genlist(curfn->enter);
pret = nil;
@@ -78,6 +81,7 @@ compile(Node *fn)
}
genlist(curfn->nbody);
+ gclean();
checklabels();
if(nerrors != 0)
goto ret;
@@ -87,29 +91,32 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
+ ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
+ gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer)
- ginscall(deferreturn, 0);
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
- /* TODO(kaib): Add back register optimizations
- if(!debug['N'] || debug['R'] || debug['P'])
+ if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
- */
+ }
// fill in argument size
ptxt->to.type = D_CONST2;
ptxt->reg = 0; // flags
- ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
if(stksize > maxstksize)
maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
if(debug['f'])
@@ -203,6 +210,7 @@ ginscall(Node *f, int proc)
void
cgen_callinter(Node *n, Node *res, int proc)
{
+ int r;
Node *i, *f;
Node tmpi, nodo, nodr, nodsp;
@@ -216,6 +224,14 @@ cgen_callinter(Node *n, Node *res, int proc)
i = i->left; // interface
+ // Release res register during genlist and cgen,
+ // which might have their own function calls.
+ r = -1;
+ if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+ r = res->val.u.reg;
+ reg[r]--;
+ }
+
if(!i->addable) {
tempname(&tmpi, i->type);
cgen(i, &tmpi);
@@ -223,6 +239,8 @@ cgen_callinter(Node *n, Node *res, int proc)
}
genlist(n->list); // args
+ if(r >= 0)
+ reg[r]++;
regalloc(&nodr, types[tptr], res);
regalloc(&nodo, types[tptr], &nodr);
@@ -427,10 +445,10 @@ cgen_asop(Node *n)
case OOR:
a = optoas(n->etype, nl->type);
if(nl->addable) {
- regalloc(&n2, nl->type, N);
regalloc(&n3, nr->type, N);
- cgen(nl, &n2);
cgen(nr, &n3);
+ regalloc(&n2, nl->type, N);
+ cgen(nl, &n2);
gins(a, &n3, &n2);
cgen(&n2, nl);
regfree(&n2);
@@ -439,13 +457,14 @@ cgen_asop(Node *n)
}
if(nr->ullman < UINF)
if(sudoaddable(a, nl, &addr, &w)) {
+ w = optoas(OAS, nl->type);
regalloc(&n2, nl->type, N);
- regalloc(&n3, nr->type, N);
- p1 = gins(AMOVW, N, &n2);
+ p1 = gins(w, N, &n2);
p1->from = addr;
+ regalloc(&n3, nr->type, N);
cgen(nr, &n3);
gins(a, &n3, &n2);
- p1 = gins(AMOVW, &n2, N);
+ p1 = gins(w, &n2, N);
p1->to = addr;
regfree(&n2);
regfree(&n3);
@@ -544,7 +563,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
cgen(nl, &n1);
sc = mpgetfix(nr->val.u.xval);
if(sc == 0) {
- return;
+ // nothing to do
} else if(sc >= nl->type->width*8) {
if(op == ORSH && issigned[nl->type->etype])
gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
@@ -682,6 +701,29 @@ regcmp(const void *va, const void *vb)
static Prog* throwpc;
+// We're only going to bother inlining if we can
+// convert all the arguments to 32 bits safely. Can we?
+static int
+fix64(NodeList *nn, int n)
+{
+ NodeList *l;
+ Node *r;
+ int i;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ r = l->n->right;
+ if(is64(r->type) && !smallintconst(r)) {
+ if(r->op == OCONV)
+ r = r->left;
+ if(is64(r->type))
+ return 0;
+ }
+ l = l->next;
+ }
+ return 1;
+}
+
void
getargs(NodeList *nn, Node *reg, int n)
{
@@ -710,7 +752,7 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
Node *c, n1, n2;
@@ -720,17 +762,8 @@ cmpandthrow(Node *nl, Node *nr)
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AB, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
// put the constant on the right
op = brrev(op);
@@ -794,6 +827,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -811,6 +846,8 @@ cgen_inline(Node *n, Node *res)
slicearray:
if(!sleasy(res))
goto no;
+ if(!fix64(n->list, 5))
+ goto no;
getargs(n->list, nodes, 5);
// if(hb[3] > nel[1]) goto throw
@@ -902,6 +939,8 @@ slicearray:
return 1;
sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index c4564ed66..bf59534b9 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -633,10 +633,10 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
// TODO(kaib): re-implement genembedtramp
- genwrapper(rcvr, method, newnam);
+ genwrapper(rcvr, method, newnam, iface);
/*
Sym *e;
int c, d, o;
@@ -705,7 +705,7 @@ out:
p->to.type = D_OREG;
p->to.reg = NREG;
p->to.name = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("4. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 700602c35..133a21b3e 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -197,9 +197,50 @@ afunclit(Addr *a)
}
}
+static int resvd[] =
+{
+ 9, // reserved for m
+ 10, // reserved for g
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 0;
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]++;
+}
+
+void
+gclean(void)
+{
+ int i;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]--;
+
+ for(i=0; i<nelem(reg); i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+}
+
int32
anyregalloc(void)
{
+ int i, j;
+
+ for(i=0; i<nelem(reg); i++) {
+ if(reg[i] == 0)
+ goto ok;
+ for(j=0; j<nelem(resvd); j++)
+ if(resvd[j] == i)
+ goto ok;
+ return 1;
+ ok:;
+ }
return 0;
}
@@ -264,6 +305,11 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
yyerror("out of floating point registers");
goto err;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
}
yyerror("regalloc: unknown type %T", t);
@@ -293,6 +339,8 @@ regfree(Node *n)
print("regalloc fix %d float %d\n", fixfree, floatfree);
}
+ if(n->op == ONAME && iscomplex[n->type->etype])
+ return;
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
@@ -498,6 +546,11 @@ gmove(Node *f, Node *t)
tt = simsimtype(t->type);
cvt = t->type;
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
// cannot have two memory operands;
// except 64-bit, which always copies via registers anyway.
if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
@@ -715,56 +768,109 @@ gmove(Node *f, Node *t)
* float to integer
*/
case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TINT32):
case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT32, TINT16):
case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TINT32):
case CASE(TFLOAT32, TUINT32):
- fa = AMOVF;
- a = AMOVFW;
- ta = AMOVW;
- goto fltconv;
+// case CASE(TFLOAT32, TUINT64):
case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TINT32):
case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT64, TINT16):
case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TINT32):
case CASE(TFLOAT64, TUINT32):
- fa = AMOVD;
- a = AMOVDW;
+// case CASE(TFLOAT64, TUINT64):
+ fa = AMOVF;
+ a = AMOVFW;
+ if(ft == TFLOAT64) {
+ fa = AMOVD;
+ a = AMOVDW;
+ }
ta = AMOVW;
- goto fltconv;
+ switch(tt) {
+ case TINT8:
+ ta = AMOVB;
+ break;
+ case TUINT8:
+ ta = AMOVBU;
+ break;
+ case TINT16:
+ ta = AMOVH;
+ break;
+ case TUINT16:
+ ta = AMOVHU;
+ break;
+ }
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- fatal("gmove TFLOAT, UINT64 not implemented");
+ regalloc(&r1, types[ft], f);
+ regalloc(&r2, types[tt], t);
+ gins(fa, f, &r1); // load to fpu
+ p1 = gins(a, &r1, &r1); // convert to w
+ switch(tt) {
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ p1->scond |= C_UBIT;
+ }
+ gins(AMOVW, &r1, &r2); // copy to cpu
+ gins(ta, &r2, t); // store
+ regfree(&r1);
+ regfree(&r2);
return;
/*
* integer to float
*/
case CASE(TINT8, TFLOAT32):
- case CASE(TINT16, TFLOAT32):
- case CASE(TINT32, TFLOAT32):
case CASE(TUINT8, TFLOAT32):
+ case CASE(TINT16, TFLOAT32):
case CASE(TUINT16, TFLOAT32):
+ case CASE(TINT32, TFLOAT32):
case CASE(TUINT32, TFLOAT32):
- fa = AMOVW;
- a = AMOVWF;
- ta = AMOVF;
- goto fltconv;
-
case CASE(TINT8, TFLOAT64):
- case CASE(TINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT64):
case CASE(TUINT8, TFLOAT64):
+ case CASE(TINT16, TFLOAT64):
case CASE(TUINT16, TFLOAT64):
+ case CASE(TINT32, TFLOAT64):
case CASE(TUINT32, TFLOAT64):
fa = AMOVW;
- a = AMOVWD;
- ta = AMOVD;
- goto fltconv;
+ switch(ft) {
+ case TINT8:
+ fa = AMOVB;
+ break;
+ case TUINT8:
+ fa = AMOVBU;
+ break;
+ case TINT16:
+ fa = AMOVH;
+ break;
+ case TUINT16:
+ fa = AMOVHU;
+ break;
+ }
+ a = AMOVWF;
+ ta = AMOVF;
+ if(tt == TFLOAT64) {
+ a = AMOVWD;
+ ta = AMOVD;
+ }
+ regalloc(&r1, types[ft], f);
+ regalloc(&r2, types[tt], t);
+ gins(fa, f, &r1); // load to cpu
+ gins(AMOVW, &r1, &r2); // copy to fpu
+ p1 = gins(a, &r2, &r2); // convert
+ switch(ft) {
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ p1->scond |= C_UBIT;
+ }
+ gins(ta, &r2, t); // store
+ regfree(&r1);
+ regfree(&r2);
+ return;
case CASE(TUINT64, TFLOAT32):
case CASE(TUINT64, TFLOAT64):
@@ -831,16 +937,6 @@ trunc64:
splitclean();
return;
-fltconv:
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1);
- gins(a, &r1, &r2);
- gins(ta, &r2, t);
- regfree(&r1);
- regfree(&r2);
- return;
-
fatal:
// should not happen
fatal("gmove %N -> %N", f, t);
@@ -951,7 +1047,7 @@ gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
{
Prog *p;
- if (sval <= 0 || sval > 32)
+ if(sval <= 0 || sval > 32)
fatal("bad shift value: %d", sval);
sval = sval&0x1f;
@@ -983,7 +1079,7 @@ checkoffset(Addr *a, int canemitcode)
if(a->offset < unmappedzero)
return;
if(!canemitcode)
- fatal("checkoffset %#llx, cannot emit code", a->offset);
+ fatal("checkoffset %#x, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit
@@ -1014,7 +1110,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case OREGISTER:
- if (n->val.u.reg <= REGALLOC_RMAX) {
+ if(n->val.u.reg <= REGALLOC_RMAX) {
a->type = D_REG;
a->reg = n->val.u.reg;
} else {
@@ -1314,15 +1410,21 @@ optoas(int op, Type *t)
case CASE(OAS, TBOOL):
case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
a = AMOVB;
break;
+ case CASE(OAS, TUINT8):
+ a = AMOVBU;
+ break;
+
case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
a = AMOVH;
break;
+ case CASE(OAS, TUINT16):
+ a = AMOVHU;
+ break;
+
case CASE(OAS, TINT32):
case CASE(OAS, TUINT32):
case CASE(OAS, TPTR32):
@@ -1554,7 +1656,7 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
int64 v;
Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
- Prog *p1;
+ Prog *p1, *p2;
Type *t;
if(n->type == T)
@@ -1579,6 +1681,8 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
goto odot;
case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
cleani += 2;
reg = &clean[cleani-1];
reg1 = &clean[cleani-2];
@@ -1692,8 +1796,8 @@ oindex:
if(issigned[r->type->etype])
t = types[TINT32];
regalloc(reg1, t, N);
- regalloc(&n3, r->type, reg1);
- cgen(r, &n3);
+ regalloc(&n3, types[TINT32], reg1);
+ p2 = cgenindex(r, &n3);
gmove(&n3, reg1);
regfree(&n3);
@@ -1734,6 +1838,8 @@ oindex:
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
regfree(&n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p2)
+ patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
@@ -1746,14 +1852,20 @@ oindex:
gmove(&n2, reg);
}
- if (*w == 1)
+ switch(*w) {
+ case 1:
gins(AADD, reg1, reg);
- else if(*w == 2)
+ break;
+ case 2:
gshift(AADD, reg1, SHIFT_LL, 1, reg);
- else if(*w == 4)
+ break;
+ case 4:
gshift(AADD, reg1, SHIFT_LL, 2, reg);
- else if(*w == 8)
+ break;
+ case 8:
gshift(AADD, reg1, SHIFT_LL, 3, reg);
+ break;
+ }
naddr(reg1, a, 1);
a->type = D_OREG;
@@ -1799,19 +1911,6 @@ oindex_const:
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, reg);
-
- } else
- if(!debug['B']) {
- if(v < 0) {
- yyerror("out of bounds on array");
- } else
- if(o & OPtrto) {
- if(v >= l->type->type->bound)
- yyerror("out of bounds on array");
- } else
- if(v >= l->type->bound) {
- yyerror("out of bounds on array");
- }
}
n2 = *reg;
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index 19027829c..ce74d6478 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -49,28 +49,28 @@ listinit(void)
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
+ char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
sconsize = 8;
switch(p->as) {
default:
+ snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
if(p->reg == NREG)
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, &p->to);
- else if (p->from.type != D_FREG)
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,R%d,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
+ p->loc, p->lineno, str1, &p->from, &p->to);
else
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,F%d,%D",
+ if (p->from.type != D_FREG) {
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D",
+ p->loc, p->lineno, str1, &p->from, p->reg, &p->to);
+ } else
+ snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D",
p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, p->reg, &p->to);
break;
}
@@ -154,10 +154,16 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- sprint(str, "%d(APC)", a->offset);
+ if(a->branch == P || a->branch->loc == 0) {
+ if(a->sym != S)
+ sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%d(APC)", a->offset);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%d(APC)", a->sym->name, a->branch->loc);
+ else
+ sprint(str, "%d(APC)", a->branch->loc);
break;
case D_FCONST:
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 1b0366290..9a4e17571 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*, Adr*);
+Bits mkvar(Reg *r, Adr *a, int);
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
new file mode 100644
index 000000000..32333e8a9
--- /dev/null
+++ b/src/cmd/5g/peep.c
@@ -0,0 +1,1511 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5g/peep.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 "gg.h"
+#include "opt.h"
+
+int xtramodes(Reg*, Adr*);
+int shiftprop(Reg *r);
+void constprop(Adr *c1, Adr *v1, Reg *r);
+void predicate(void);
+int copyau1(Prog *p, Adr *v);
+int isdconst(Addr *a);
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ /*
+ * elide shift into D_SHIFT operand of subsequent instruction
+ */
+ if(shiftprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ break;
+
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ if(!regtyp(&p->to))
+ 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)
+ break;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AEOR:
+ /*
+ * EOR -1,x,y => MVN x,y
+ */
+ if(isdconst(&p->from) && p->from.offset == -1) {
+ p->as = AMVN;
+ p->from.type = D_REG;
+ if(p->reg != NREG)
+ p->from.reg = p->reg;
+ else
+ p->from.reg = p->to.reg;
+ p->reg = NREG;
+ }
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ 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;
+ }
+ }
+
+ predicate();
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG)
+ return 1;
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ABL:
+ return 0;
+
+ case ACMP:
+ case ACMN:
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+
+ case AMOVM:
+ t = 1<<v2->reg;
+ if((p->from.type == D_CONST && (p->from.offset&t)) ||
+ (p->to.type == D_CONST && (p->to.offset&t)))
+ return 0;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant constants.
+ * $c1->v1
+ * ($c1->v2 s/$c1/v1)*
+ * set v1 return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Adr *c1, Adr *v1, Reg *r)
+{
+ Prog *p;
+
+ if(debug['P'])
+ print("constprop %D->%D\n", c1, v1);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(uniqp(r) == R) {
+ if(debug['P'])
+ print("; merge; return\n");
+ return;
+ }
+ if(p->as == AMOVW && copyas(&p->from, c1)) {
+ if(debug['P'])
+ print("; sub%D/%D", &p->from, v1);
+ p->from = *v1;
+ } else if(copyu(p, v1, A) > 1) {
+ if(debug['P'])
+ print("; %Dset; return\n", v1);
+ return;
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ constprop(c1, v1, r->s2);
+ }
+}
+
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+#define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
+int
+shiftprop(Reg *r)
+{
+ Reg *r1;
+ Prog *p, *p1, *p2;
+ int n, o;
+ Adr a;
+
+ p = r->prog;
+ if(p->to.type != D_REG)
+ FAIL("BOTCH: result not reg");
+ n = p->to.reg;
+ a = zprog.from;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a.type = D_REG;
+ a.reg = p->reg;
+ }
+ if(debug['P'])
+ print("shiftprop\n%P", p);
+ r1 = r;
+ for(;;) {
+ /* find first use of shift result; abort if shift operands or result are changed */
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("branch");
+ if(uniqp(r1) == R)
+ FAIL("merge");
+ p1 = r1->prog;
+ if(debug['P'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
+ (a.type == D_REG && copyu(p1, &a, A) > 1))
+ FAIL("args modified");
+ continue;
+ case 3: /* set, not used */
+ FAIL("BOTCH: noref");
+ }
+ break;
+ }
+ /* check whether substitution can be done */
+ switch(p1->as) {
+ default:
+ FAIL("non-dpi");
+ case AAND:
+ case AEOR:
+ case AADD:
+ case AADC:
+ case AORR:
+ case ASUB:
+ case ARSB:
+ case ASBC:
+ case ARSC:
+ if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
+ if(p1->from.type != D_REG)
+ FAIL("can't swap");
+ p1->reg = p1->from.reg;
+ p1->from.reg = n;
+ switch(p1->as) {
+ case ASUB:
+ p1->as = ARSB;
+ break;
+ case ARSB:
+ p1->as = ASUB;
+ break;
+ case ASBC:
+ p1->as = ARSC;
+ break;
+ case ARSC:
+ p1->as = ASBC;
+ break;
+ }
+ if(debug['P'])
+ print("\t=>%P", p1);
+ }
+ case ABIC:
+ case ACMP:
+ case ACMN:
+ if(p1->reg == n)
+ FAIL("can't swap");
+ if(p1->reg == NREG && p1->to.reg == n)
+ FAIL("shift result used twice");
+ case AMVN:
+ if(p1->from.type == D_SHIFT)
+ FAIL("shift result used in shift");
+ if(p1->from.type != D_REG || p1->from.reg != n)
+ FAIL("BOTCH: where is it used?");
+ break;
+ }
+ /* check whether shift result is used subsequently */
+ p2 = p1;
+ if(p1->to.reg != n)
+ for (;;) {
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("inconclusive");
+ p1 = r1->prog;
+ if(debug['P'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ continue;
+ case 3: /* set, not used */
+ break;
+ default:/* used */
+ FAIL("reused");
+ }
+ break;
+ }
+
+ /* make the substitution */
+ p2->from.type = D_SHIFT;
+ p2->from.reg = NREG;
+ o = p->reg;
+ if(o == NREG)
+ o = p->to.reg;
+
+ switch(p->from.type){
+ case D_CONST:
+ o |= (p->from.offset&0x1f)<<7;
+ break;
+ case D_REG:
+ o |= (1<<4) | (p->from.reg<<8);
+ break;
+ }
+ switch(p->as){
+ case ASLL:
+ o |= 0<<5;
+ break;
+ case ASRL:
+ o |= 1<<5;
+ break;
+ case ASRA:
+ o |= 2<<5;
+ break;
+ }
+ p2->from.offset = o;
+ if(debug['P'])
+ print("\t=>%P\tSUCCEED\n", p2);
+ return 1;
+}
+
+Reg*
+findpre(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
+ if(uniqs(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ return R;
+ case 3: /* set */
+ case 4: /* set and used */
+ return r1;
+ }
+ }
+ return R;
+}
+
+Reg*
+findinc(Reg *r, Reg *r2, Adr *v)
+{
+ Reg *r1;
+ Prog *p;
+
+
+ for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
+ if(uniqp(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 0: /* not touched */
+ continue;
+ case 4: /* set and used */
+ p = r1->prog;
+ if(p->as == AADD)
+ if(isdconst(&p->from))
+ if(p->from.offset > -4096 && p->from.offset < 4096)
+ return r1;
+ default:
+ return R;
+ }
+ }
+ return R;
+}
+
+int
+nochange(Reg *r, Reg *r2, Prog *p)
+{
+ Adr a[3];
+ int i, n;
+
+ if(r == r2)
+ return 1;
+ n = 0;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a[n].type = D_REG;
+ a[n++].reg = p->reg;
+ }
+ switch(p->from.type) {
+ case D_SHIFT:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.offset&0xf;
+ case D_REG:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.reg;
+ }
+ if(n == 0)
+ return 1;
+ for(; r!=R && r!=r2; r=uniqs(r)) {
+ p = r->prog;
+ for(i=0; i<n; i++)
+ if(copyu(p, &a[i], A) > 1)
+ return 0;
+ }
+ return 1;
+}
+
+int
+findu1(Reg *r, Adr *v)
+{
+ for(; r != R; r = r->s1) {
+ if(r->active)
+ return 0;
+ r->active = 1;
+ switch(copyu(r->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ case 4: /* set and used */
+ return 1;
+ case 3: /* set */
+ return 0;
+ }
+ if(r->s2)
+ if (findu1(r->s2, v))
+ return 1;
+ }
+ return 0;
+}
+
+int
+finduse(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=firstr; r1!=R; r1=r1->link)
+ r1->active = 0;
+ return findu1(r, v);
+}
+
+int
+xtramodes(Reg *r, Adr *a)
+{
+ Reg *r1, *r2, *r3;
+ Prog *p, *p1;
+ Adr v;
+
+ p = r->prog;
+ if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */
+ return 0;
+ v = *a;
+ v.type = D_REG;
+ r1 = findpre(r, &v);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p1->to.type == D_REG && p1->to.reg == v.reg)
+ switch(p1->as) {
+ case AADD:
+ if(p1->from.type == D_REG ||
+ (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+ (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
+ (p1->from.type == D_CONST &&
+ p1->from.offset > -4096 && p1->from.offset < 4096))
+ if(nochange(uniqs(r1), r, p1)) {
+ if(a != &p->from || v.reg != p->to.reg)
+ if (finduse(r->s1, &v)) {
+ if(p1->reg == NREG || p1->reg == v.reg)
+ /* pre-indexing */
+ p->scond |= C_WBIT;
+ else return 0;
+ }
+ switch (p1->from.type) {
+ case D_REG:
+ /* register offset */
+ a->type = D_SHIFT;
+ a->offset = p1->from.reg;
+ break;
+ case D_SHIFT:
+ /* scaled register offset */
+ a->type = D_SHIFT;
+ case D_CONST:
+ /* immediate offset */
+ a->offset = p1->from.offset;
+ break;
+ }
+ if(p1->reg != NREG)
+ a->reg = p1->reg;
+ excise(r1);
+ return 1;
+ }
+ break;
+ case AMOVW:
+ if(p1->from.type == D_REG)
+ if((r2 = findinc(r1, r, &p1->from)) != R) {
+ for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
+ ;
+ if(r3 == r) {
+ /* post-indexing */
+ p1 = r2->prog;
+ a->reg = p1->to.reg;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ if(!finduse(r, &r1->prog->to))
+ excise(r1);
+ excise(r2);
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+ if(a != &p->from || a->reg != p->to.reg)
+ if((r1 = findinc(r, R, &v)) != R) {
+ /* post-indexing */
+ p1 = r1->prog;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ excise(r1);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (?)");
+ return 2;
+
+ case AMOVM:
+ if(v->type != D_REG)
+ return 0;
+ if(p->from.type == D_CONST) { /* read reglist, read/rar */
+ if(s != A) {
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ return 1;
+ }
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ } else { /* read/rar, write reglist */
+ if(s != A) {
+ if(p->to.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->from, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ if(p->to.offset&(1<<v->reg))
+ return 4;
+ return 1;
+ }
+ if(p->to.offset&(1<<v->reg))
+ return 3;
+ }
+ return 0;
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(p->scond&(C_WBIT|C_PBIT))
+ if(v->type == D_REG) {
+ if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+ if(p->from.reg == v->reg)
+ return 2;
+ } else {
+ if(p->to.reg == v->reg)
+ return 2;
+ }
+ }
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case AADD: /* read, read, write */
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+
+ case ACMPF:
+ case ACMPD:
+ case ACMP:
+ case ACMN:
+ case ACASE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AB: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case ABL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+
+ case ACMP:
+ case ACMN:
+
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPF:
+ case ACMPD:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ } else
+ if(v->type == D_CONST) { /* for constprop */
+ if(a->type == v->type)
+ if(a->name == v->name)
+ if(a->sym == v->sym)
+ if(a->reg == v->reg)
+ if(a->offset == v->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG) {
+ if(a->type == D_CONST && a->reg != NREG) {
+ if(v->reg == a->reg)
+ return 1;
+ } else
+ if(a->type == D_OREG) {
+ if(v->reg == a->reg)
+ return 1;
+ } else
+ if(a->type == D_REGREG) {
+ if(v->reg == a->reg)
+ return 1;
+ if(a->offset == v->reg)
+ return 1;
+ } else
+ if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ return 1;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a2type(p) == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v)) {
+ if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ a->offset = (a->offset&~0xf)|s->reg;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+ } else
+ if(a->type == D_REGREG) {
+ if(a->offset == v->reg)
+ a->offset = s->reg;
+ if(a->reg == v->reg)
+ a->reg = s->reg;
+ } else
+ a->reg = s->reg;
+ }
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
+
+struct {
+ int opcode;
+ int notopcode;
+ int scond;
+ int notscond;
+} predinfo[] = {
+ { ABEQ, ABNE, 0x0, 0x1, },
+ { ABNE, ABEQ, 0x1, 0x0, },
+ { ABCS, ABCC, 0x2, 0x3, },
+ { ABHS, ABLO, 0x2, 0x3, },
+ { ABCC, ABCS, 0x3, 0x2, },
+ { ABLO, ABHS, 0x3, 0x2, },
+ { ABMI, ABPL, 0x4, 0x5, },
+ { ABPL, ABMI, 0x5, 0x4, },
+ { ABVS, ABVC, 0x6, 0x7, },
+ { ABVC, ABVS, 0x7, 0x6, },
+ { ABHI, ABLS, 0x8, 0x9, },
+ { ABLS, ABHI, 0x9, 0x8, },
+ { ABGE, ABLT, 0xA, 0xB, },
+ { ABLT, ABGE, 0xB, 0xA, },
+ { ABGT, ABLE, 0xC, 0xD, },
+ { ABLE, ABGT, 0xD, 0xC, },
+};
+
+typedef struct {
+ Reg *start;
+ Reg *last;
+ Reg *end;
+ int len;
+} Joininfo;
+
+enum {
+ Join,
+ Split,
+ End,
+ Branch,
+ Setcond,
+ Toolong
+};
+
+enum {
+ Falsecond,
+ Truecond,
+ Delbranch,
+ Keepbranch
+};
+
+int
+isbranch(Prog *p)
+{
+ return (ABEQ <= p->as) && (p->as <= ABLE);
+}
+
+int
+predicable(Prog *p)
+{
+ switch(p->as) {
+ case ANOP:
+ case AXXX:
+ case ADATA:
+ case AGLOBL:
+ case AGOK:
+ case AHISTORY:
+ case ANAME:
+ case ASIGNAME:
+ case ATEXT:
+ case AWORD:
+ case ABCASE:
+ case ACASE:
+ return 0;
+ }
+ if(isbranch(p))
+ return 0;
+ return 1;
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+int
+modifiescpsr(Prog *p)
+{
+ switch(p->as) {
+ case ATST:
+ case ATEQ:
+ case ACMN:
+ case ACMP:
+ case AMULU:
+ case ADIVU:
+ case AMUL:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case ABL:
+ return 1;
+ }
+ if(p->scond & C_SBIT)
+ return 1;
+ return 0;
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+int
+joinsplit(Reg *r, Joininfo *j)
+{
+ j->start = r;
+ j->last = r;
+ j->len = 0;
+ do {
+ if (r->p2 && (r->p1 || r->p2->p2link)) {
+ j->end = r;
+ return Join;
+ }
+ if (r->s1 && r->s2) {
+ j->end = r;
+ return Split;
+ }
+ j->last = r;
+ if (r->prog->as != ANOP)
+ j->len++;
+ if (!r->s1 && !r->s2) {
+ j->end = r->link;
+ return End;
+ }
+ if (r->s2) {
+ j->end = r->s2;
+ return Branch;
+ }
+ if (modifiescpsr(r->prog)) {
+ j->end = r->s1;
+ return Setcond;
+ }
+ r = r->s1;
+ } while (j->len < 4);
+ j->end = r;
+ return Toolong;
+}
+
+Reg*
+successor(Reg *r)
+{
+ if(r->s1)
+ return r->s1;
+ else
+ return r->s2;
+}
+
+void
+applypred(Reg *rstart, Joininfo *j, int cond, int branch)
+{
+ int pred;
+ Reg *r;
+
+ if(j->len == 0)
+ return;
+ if(cond == Truecond)
+ pred = predinfo[rstart->prog->as - ABEQ].scond;
+ else
+ pred = predinfo[rstart->prog->as - ABEQ].notscond;
+
+ for(r = j->start;; r = successor(r)) {
+ if (r->prog->as == AB) {
+ if (r != j->last || branch == Delbranch)
+ excise(r);
+ else {
+ if (cond == Truecond)
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
+ else
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
+ }
+ }
+ else
+ if (predicable(r->prog))
+ r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
+ if (r->s1 != r->link) {
+ r->s1 = r->link;
+ r->link->p1 = r;
+ }
+ if (r == j->last)
+ break;
+ }
+}
+
+void
+predicate(void)
+{
+ Reg *r;
+ int t1, t2;
+ Joininfo j1, j2;
+
+ for(r=firstr; r!=R; r=r->link) {
+ if (isbranch(r->prog)) {
+ t1 = joinsplit(r->s1, &j1);
+ t2 = joinsplit(r->s2, &j2);
+ if(j1.last->link != j2.start)
+ continue;
+ if(j1.end == j2.end)
+ if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
+ (t2 == Join && (t1 == Join || t1 == Setcond))) {
+ applypred(r, &j1, Falsecond, Delbranch);
+ applypred(r, &j2, Truecond, Delbranch);
+ excise(r);
+ continue;
+ }
+ if(t1 == End || t1 == Branch) {
+ applypred(r, &j1, Falsecond, Keepbranch);
+ excise(r);
+ continue;
+ }
+ }
+ }
+}
+
+int
+isdconst(Addr *a)
+{
+ if(a->type == D_CONST && a->reg == NREG)
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
new file mode 100644
index 000000000..5011e75cc
--- /dev/null
+++ b/src/cmd/5g/reg.c
@@ -0,0 +1,1329 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5g/reg.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 "gg.h"
+#include "opt.h"
+
+#define P2R(p) (Reg*)(p->reg)
+
+ void addsplits(void);
+ int noreturn(Prog *p);
+static int first = 0;
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = mal(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+static void
+setoutvar(void)
+{
+ Type *t;
+ Node *n;
+ Addr a;
+ Iter save;
+ Bits bit;
+ int z;
+
+ t = structfirst(&save, getoutarg(curfn->type));
+ while(t != T) {
+ n = nodarg(t, 1);
+ a = zprog.from;
+ naddr(n, &a, 0);
+ bit = mkvar(R, &a, 0);
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+ t = structnext(&save);
+ }
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->scond = zprog.scond;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg;
+}
+
+static void
+setaddrs(Bits bit)
+{
+ int i, n;
+ Var *v;
+ Sym *s;
+
+ while(bany(&bit)) {
+ // convert each bit to a variable
+ i = bnum(bit);
+ s = var[i].sym;
+ n = var[i].name;
+ bit.b[i/32] &= ~(1L<<(i%32));
+
+ // disable all pieces of that variable
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->sym == s && v->name == n)
+ v->addr = 2;
+ }
+ }
+}
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+return; // disabled for the moment
+ if(first == 0) {
+ fmtinstall('Q', Qconv);
+ }
+ first++;
+
+ if(debug['K']) {
+ if(first != 20)
+ return;
+// debug['R'] = 2;
+// debug['P'] = 2;
+ print("optimizing %S\n", curfn->nname->sym);
+ }
+
+ // count instructions
+ nr = 0;
+ for(p=firstp; p!=P; p=p->link)
+ nr++;
+
+ // if too big dont bother
+ if(nr >= 10000) {
+// print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
+ return;
+ }
+
+ r1 = R;
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ ovar.b[z] = 0;
+ }
+
+ // build list of return variables
+ setoutvar();
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ nr = 0;
+ for(p=firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ nr++;
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ p->regp = r;
+
+ r1 = r->p1;
+ if(r1 != R) {
+ switch(r1->prog->as) {
+ case ARET:
+ case AB:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(r, &p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(r, &p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ if(p->as == AMOVM) {
+ z = p->to.offset;
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R)
+ return;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ if(p->to.branch == P)
+ fatal("pnil %P", p);
+ r1 = p->to.branch->regp;
+ if(r1 == R)
+ fatal("rnil %P", p);
+ if(r1 == r) {
+ //fatal("ref to self %P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, nr);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] > 1) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++) {
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ }
+
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%Q", r->use2);
+ if(bany(&r->set))
+ print(" st=%Q", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%Q", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%Q", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%Q", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%Q", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit) & !r->refset) {
+ // should never happen - all variables are preset
+ if(debug['w'])
+ print("%L: used and not set: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit) && !r->refset) {
+ if(debug['w'])
+ print("%L: set and not used: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] > 1)
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %Q\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] > 1)
+ print("too many regions\n");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %Q\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %Q\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P']) {
+// peep();
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ 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(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == ABL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = mal(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ 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 TINT16:
+ case TUINT16:
+ p1->as = AMOVH;
+ break;
+ case TFLOAT32:
+ p1->as = AMOVF;
+ break;
+ case TFLOAT64:
+ p1->as = AMOVD;
+ break;
+ }
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUINT8)
+ p1->as = AMOVBU;
+ if(v->etype == TUINT16)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+static int
+overlap(int32 o1, int w1, int32 o2, int w2)
+{
+ int32 t1, t2;
+
+ t1 = o1+w1;
+ t2 = o2+w2;
+
+ if(!(t1 > o2 && t2 > o1))
+ return 0;
+
+ return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z, w, flag;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ // mark registers used
+ t = a->type;
+ n = D_NONE;
+
+ 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;
+
+ case D_REGREG:
+ if(a->offset != NREG)
+ r->regu |= RtoB(a->offset);
+ // fallthrough
+
+ case D_REG:
+ case D_SHIFT:
+ case D_OREG:
+ if(a->reg != NREG)
+ r->regu |= RtoB(a->reg);
+ break;
+
+ case D_FREG:
+ if(a->reg != NREG)
+ r->regu |= FtoB(a->reg);
+ break;
+ }
+
+ switch(a->name) {
+ default:
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ n = a->name;
+ break;
+ }
+
+ flag = 0;
+// if(a->pun)
+// flag = 1;
+
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->sym == s && v->name == n) {
+ if(v->offset == o)
+ if(v->etype == et)
+ if(v->width == w)
+ if(!flag)
+ return blsh(i);
+
+ // if they overlaps, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ case TARRAY:
+ case TSTRING:
+ goto none;
+ }
+
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ fatal("variable not optimized: %D", a);
+ goto none;
+ }
+
+ i = nvar;
+ nvar++;
+ v = var+i;
+ v->sym = s;
+ v->offset = o;
+ v->name = n;
+// v->gotype = a->gotype;
+ v->etype = et;
+ v->width = w;
+ v->addr = flag; // funny punning
+
+ 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++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ 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:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABL:
+ if(noreturn(r1->prog))
+ break;
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z] | ovar.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+ int32 t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal("bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+ int32 src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, int32 head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, int32 nr)
+{
+ Reg *r1;
+ int32 i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = mal(nr * sizeof(Reg*));
+ idom = mal(nr * sizeof(int32));
+ maxnr = nr;
+ }
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal("too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ fatal("unknown etype %d/%E", bitno(b), v->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ case TINTER:
+ case TSTRUCT:
+ case TARRAY:
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\td %Q $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu1 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu2 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tst %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ 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;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 10 R10
+ */
+int32
+RtoB(int r)
+{
+
+ if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
+ return 0;
+ return 1L << r;
+}
+
+int
+BtoR(int32 b)
+{
+ b &= 0x01fcL; // excluded R9 and R10 for m and g
+ if(b == 0)
+ return 0;
+ return bitno(b);
+}
+
+/*
+ * bit reg
+ * 18 F2
+ * 19 F3
+ * ... ...
+ * 23 F7
+ */
+int32
+FtoB(int f)
+{
+
+ if(f < 2 || f > NFREG-1)
+ return 0;
+ return 1L << (f + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+ b &= 0xfc0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16;
+}
+
+static Sym* symlist[10];
+
+int
+noreturn(Prog *p)
+{
+ Sym *s;
+ int i;
+
+ if(symlist[0] == S) {
+ symlist[0] = pkglookup("panicindex", runtimepkg);
+ symlist[1] = pkglookup("panicslice", runtimepkg);
+ symlist[2] = pkglookup("throwinit", runtimepkg);
+ symlist[3] = pkglookup("panic", runtimepkg);
+ }
+
+ s = p->to.sym;
+ if(s == S)
+ return 0;
+ for(i=0; symlist[i]!=S; i++)
+ if(s == symlist[i])
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index c06441c1c..a25c0f71d 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -58,6 +58,7 @@
#define NFREG 8
#define FREGRET 0
#define FREGEXT 7
+#define FREGTMP 15
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
@@ -158,8 +159,8 @@ enum as
ARET,
ATEXT,
AWORD,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ABCASE,
ACASE,
@@ -188,7 +189,7 @@ enum as
#define C_PBIT (1<<5)
#define C_WBIT (1<<6)
#define C_FBIT (1<<7) /* psr flags-only */
-#define C_UBIT (1<<7) /* up bit */
+#define C_UBIT (1<<7) /* up bit, unsigned bit */
#define C_SCOND_EQ 0
#define C_SCOND_NE 1
@@ -246,6 +247,7 @@ enum as
/* internal only */
#define D_SIZE (D_NONE+40)
+#define D_PCREL (D_NONE+41)
/*
* this is the ranlib header
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index b9780f098..71798724b 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -2,24 +2,29 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5l\
+TARG=5l
OFILES=\
asm.$O\
+ data.$O\
elf.$O\
enam.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
noop.$O\
obj.$O\
optab.$O\
pass.$O\
+ prof.$O\
thumb.$O\
softfloat.$O\
span.$O\
+ symtab.$O\
go.$O\
HFILES=\
@@ -27,19 +32,12 @@ HFILES=\
../5l/5.out.h\
../ld/elf.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 5.out.h
sh mkenam
-clean:
- rm -f *.o $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+CLEANFILES+=enam.c
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 45e6e734f..7ceea59b6 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -50,127 +52,11 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- case SLEAF:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > NSNAME)
- m = NSNAME;
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- p->to.sval = mal(NSNAME);
- memmove(p->to.sval, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
enum {
ElfStrEmpty,
ElfStrInterp,
@@ -188,6 +74,8 @@ enum {
ElfStrGosymtab,
ElfStrGopclntab,
ElfStrShstrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
NElfStr
};
@@ -209,21 +97,67 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ diag("adddynrel: unsupported binary format");
+}
+
+void
+adddynsym(Sym *s)
+{
+ diag("adddynsym: not implemented");
+}
+
+static void
+elfsetupplt(void)
+{
+ // TODO
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ return -1;
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
+ addstring(shstrtab, ".rodata");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
@@ -241,6 +175,8 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+ elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* interpreter string */
s = lookup(".interp", 0);
@@ -257,7 +193,8 @@ doelf(void)
s = lookup(".dynstr", 0);
s->type = SELFDATA;
s->reachable = 1;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -269,92 +206,35 @@ doelf(void)
s = lookup(".got", 0);
s->reachable = 1;
s->type = SELFDATA;
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
- /* got.plt - ??? */
+ /* got.plt */
s = lookup(".got.plt", 0);
s->reachable = 1;
- s->type = SELFDATA;
+ s->type = SDATA; // writable, so not SELFDATA
- /* hash */
- s = lookup(".hash", 0);
+ s = lookup(".plt", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
+
+ s = lookup(".rel.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
+
+ elfsetupplt();
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
-
- /*
- * relocation entries for dynimp symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rel", 0);
- addaddr(d, s);
- adduint32(d, ELF32_R_INFO(nsym, R_ARM_ABS32));
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* value */
- if(!s->dynexport)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
-
- elfdynhash(nsym);
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -365,6 +245,10 @@ doelf(void)
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_REL);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -372,16 +256,18 @@ doelf(void)
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT)
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
- diag("datoff %#llx", addr);
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
+ diag("datoff %#x", addr);
return 0;
}
void
shsym(Elf64_Shdr *sh, Sym *s)
{
- sh->addr = s->value + INITDAT;
+ sh->addr = symaddr(s);
sh->off = datoff(sh->addr);
sh->size = s->size;
}
@@ -400,103 +286,47 @@ phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
void
asmb(void)
{
- Prog *p;
- int32 t, etext;
+ int32 t;
int a, dynsym;
- uint32 va, fo, w, symo, startva;
- uint32 symdatva = SYMDATVA;
+ uint32 va, fo, w, startva;
int strtabsize;
- Optab *o;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
strtabsize = 0;
- symo = 0;
if(debug['v'])
- Bprint(&bso, "%5.2f asm\n", cputime());
+ Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- OFFSET = HEADR;
- seek(cout, OFFSET, 0);
- pc = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- }
- if(p->pc != pc) {
- diag("phase error %lux sb %lux",
- p->pc, pc);
- if(!debug['a'])
- prasm(curp);
- pc = p->pc;
- }
- curp = p;
- o = oplook(p); /* could probably avoid this call */
- if(thumb)
- thumbasmout(p, o);
- else
- asmout(p, o);
- pc += o->size;
- }
- while(pc-INITTEXT < textsize) {
- cput(0);
- pc++;
- }
- if(debug['a'])
- Bprint(&bso, "\n");
- Bflush(&bso);
- cflush();
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
- /* output strings in text segment */
- etext = INITTEXT + textsize;
- for(t = pc; t < etext; t += sizeof(buf)-100) {
- if(etext-t > sizeof(buf)-100)
- datblk(t, sizeof(buf)-100, 1);
- else
- datblk(t, etext-t, 1);
- }
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
- /* output section header strings */
- curtext = P;
- switch(HEADTYPE) {
- case 0:
- case 1:
- case 2:
- case 5:
- OFFSET = HEADR+textsize;
- seek(cout, OFFSET, 0);
- break;
- case 3:
- OFFSET = rnd(HEADR+textsize, 4096);
- seek(cout, OFFSET, 0);
- break;
- case 6:
- OFFSET = rnd(HEADR+textsize, INITRND);
- seek(cout, OFFSET, 0);
- break;
- }
- if(dlm){
- char buf[8];
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
- for(t = 0; t < datsize; t += sizeof(buf)-100) {
- if(datsize-t > sizeof(buf)-100)
- datblk(t, sizeof(buf)-100, 0);
- else
- datblk(t, datsize-t, 0);
- }
- cflush();
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
/* output symbol table */
symsize = 0;
lcsize = 0;
if(!debug['s']) {
+ // TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
@@ -508,45 +338,24 @@ asmb(void)
debug['s'] = 1;
break;
case 2:
- OFFSET = HEADR+textsize+datsize;
+ OFFSET = HEADR+textsize+segdata.filelen;
seek(cout, OFFSET, 0);
break;
case 3:
- OFFSET += rnd(datsize, 4096);
+ OFFSET += rnd(segdata.filelen, 4096);
seek(cout, OFFSET, 0);
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+datsize+strtabsize;
- symo = rnd(symo, INITRND);
- seek(cout, symo + 8, 0);
+ OFFSET += segdata.filelen;
+ seek(cout, rnd(OFFSET, INITRND), 0);
break;
}
if(!debug['s'])
- asmsym();
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- asmlc();
- if(!debug['s'])
asmthumbmap();
- if(dlm)
- asmdyn();
- if(!debug['s'])
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
- seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- }
- else if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
cflush();
}
- curtext = P;
+ cursym = nil;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
@@ -568,10 +377,10 @@ asmb(void)
lputl(0xef000011); /* SWI - exit code */
lputl(textsize+HEADR); /* text size */
- lputl(datsize); /* data size */
+ lputl(segdata.filelen); /* data size */
lputl(0); /* sym size */
- lputl(bsssize); /* bss size */
+ lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* sym type */
lputl(INITTEXT-HEADR); /* text addr */
lputl(0); /* workspace - ignored */
@@ -586,13 +395,10 @@ asmb(void)
lputl(0xe1a0f00e); /* B (R14) - zero init return */
break;
case 2: /* plan 9 */
- if(dlm)
- lput(0x80000000|0x647); /* magic */
- else
- lput(0x647); /* magic */
+ lput(0x647); /* magic */
lput(textsize); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(0L);
@@ -601,8 +407,8 @@ asmb(void)
case 3: /* boot for NetBSD */
lput((143<<16)|0413); /* magic */
lputl(rnd(HEADR+textsize, 4096));
- lputl(rnd(datsize, 4096));
- lputl(bsssize);
+ lputl(rnd(segdata.filelen, 4096));
+ lputl(segdata.len - segdata.filelen);
lputl(symsize); /* nsyms */
lputl(entryvalue()); /* va of entry */
lputl(0L);
@@ -650,41 +456,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- ph->vaddr = va;
- ph->paddr = va;
- ph->off = fo;
- ph->filesz = w;
- ph->memsz = w;
- ph->align = INITRND;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s']) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -766,81 +539,23 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
- fo = ELFRESERVE;
- va = startva + fo;
- w = textsize;
-
- /*
- * The alignments are bigger than they really need
- * to be here, but they are necessary to keep the
- * arm strip from moving everything around.
- */
-
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = ELFRESERVE;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = INITRND;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
- sh->addralign = INITRND;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
-
- sh = newElfShdr(elfstr[ElfStrGosymtab]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
-
- fo += w;
- w = lcsize;
+ shsym(sh, lookup("symtab", 0));
sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8 + lcsize;
+ shsym(sh, lookup("pclntab", 0));
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -879,27 +594,16 @@ asmb(void)
}
cflush();
if(debug['c']){
- print("textsize=%ld\n", textsize);
- print("datsize=%ld\n", datsize);
- print("bsssize=%ld\n", bsssize);
- print("symsize=%ld\n", symsize);
- print("lcsize=%ld\n", lcsize);
- print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize);
+ print("textsize=%d\n", textsize);
+ print("datsize=%d\n", segdata.filelen);
+ print("bsssize=%d\n", segdata.len - segdata.filelen);
+ print("symsize=%d\n", symsize);
+ print("lcsize=%d\n", lcsize);
+ print("total=%d\n", textsize+segdata.len+symsize+lcsize);
}
}
void
-strnput(char *s, int n)
-{
- for(; *s; s++){
- cput(*s);
- n--;
- }
- for(; n > 0; n--)
- cput(0);
-}
-
-void
cput(int c)
{
cbp[0] = c;
@@ -987,7 +691,7 @@ cflush(void)
/* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
@@ -996,223 +700,16 @@ void
nopstat(char *f, Count *c)
{
if(c->outof)
- Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ Bprint(&bso, "%s delay %d/%d (%.2f)\n", f,
c->outof - c->count, c->outof,
(double)(c->outof - c->count)/c->outof);
}
-void
-asmsym(void)
-{
- Prog *p;
- Auto *a;
- Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version);
-
- for(h=0; h<NHASH; h++)
- for(s=hash[h]; s!=S; s=s->link)
- switch(s->type) {
- case SCONST:
- putsymb(s->name, 'D', s->value, s->version);
- continue;
-
- case SDATA:
- case SELFDATA:
- putsymb(s->name, 'D', s->value+INITDAT, s->version);
- continue;
-
- case SBSS:
- putsymb(s->name, 'B', s->value+INITDAT, s->version);
- continue;
-
- case SFIXED:
- putsymb(s->name, 'B', s->value, s->version);
- continue;
-
- case SSTRING:
- putsymb(s->name, 'T', s->value, s->version);
- continue;
-
- case SFILE:
- putsymb(s->name, 'f', s->value, s->version);
- continue;
- }
-
- for(p=textp; p!=P; p=p->cond) {
- s = p->from.sym;
- if(s->type != STEXT && s->type != SLEAF)
- continue;
-
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0);
- else
- if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0);
-
- if(!s->reachable)
- continue;
-
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version);
- else
- putsymb(s->name, 'L', s->value, s->version);
-
- /* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0);
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0);
- else
- if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
-}
-
-void
-putsymb(char *s, int t, int32 v, int ver)
-{
- int i, f;
-
- if(t == 'f')
- s++;
- lput(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- // TODO(rsc): handle go parameter
- lput(0);
-
- symsize += 4 + 1 + i + 1 + 4;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8lux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
- }
- Bprint(&bso, "\n");
- return;
- }
- if(ver)
- Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
- else
- Bprint(&bso, "%c %.8lux %s\n", t, v, s);
- }
-}
-
-#define MINLC 4
-void
-asmlc(void)
-{
- int32 oldpc, oldlc;
- Prog *p;
- int32 v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['L'])
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- continue;
- }
- if(debug['L'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['L'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['L']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
- }
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
- }
- if(debug['v'] || debug['L'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
-}
-
static void
outt(int32 f, int32 l)
{
if(debug['L'])
- Bprint(&bso, "tmap: %lux-%lux\n", f, l);
+ Bprint(&bso, "tmap: %ux-%ux\n", f, l);
lput(f);
lput(l);
}
@@ -1227,186 +724,46 @@ asmthumbmap(void)
return;
pc = 0;
lastt = -1;
- for(p = firstp; p != P; p = p->link){
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
pc = p->pc - INITTEXT;
- if(p->as == ATEXT){
- setarch(p);
- if(thumb){
- if(p->from.sym->foreign){ // 8 bytes of ARM first
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- pc += 8;
- }
- if(lastt < 0)
- lastt = pc;
- }
- else{
- if(p->from.sym->foreign){ // 4 bytes of THUMB first
- if(lastt < 0)
- lastt = pc;
- pc += 4;
- }
+ setarch(p);
+ if(thumb){
+ if(p->from.sym->foreign){ // 8 bytes of ARM first
if(lastt >= 0){
outt(lastt, pc-1);
lastt = -1;
}
+ pc += 8;
}
+ if(lastt < 0)
+ lastt = pc;
}
- }
- if(lastt >= 0)
- outt(lastt, pc+1);
-}
-
-void
-datblk(int32 s, int32 n, int str)
-{
- Sym *v;
- Prog *p;
- char *cast;
- int32 a, l, fl, j, d;
- int i, c;
-
- memset(buf.dbuf, 0, n+100);
- for(p = datap; p != P; p = p->link) {
- if(str != (p->from.sym->type == SSTRING))
- continue;
- curp = p;
- a = p->from.sym->value + p->from.offset;
- l = a - s;
- c = p->reg;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
- continue;
- while(l < 0) {
- l++;
- i++;
- }
- }
- if(l >= n)
- continue;
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization");
- break;
- }
- }
- switch(p->to.type) {
- default:
- diag("unknown mode in initialization%P", p);
- break;
-
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(p->to.ieee);
- cast = (char*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (char*)p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.sval[i];
- l++;
- }
- break;
-
- case D_CONST:
- d = p->to.offset;
- v = p->to.sym;
- if(v) {
- switch(v->type) {
- case SUNDEF:
- ckoff(v, d);
- d += v->value;
- break;
- case STEXT:
- case SLEAF:
- d += v->value;
-#ifdef CALLEEBX
- d += fnpinc(v);
-#else
- if(v->thumb)
- d++; // T bit
-#endif
- break;
- case SSTRING:
- d += v->value;
- break;
- case SDATA:
- case SBSS:
- if(p->to.type == D_SIZE)
- d += v->size;
- else
- d += v->value + INITDAT;
- break;
- }
- if(dlm)
- dynreloc(v, a+INITDAT, 1);
- }
- cast = (char*)&d;
- switch(c) {
- default:
- diag("bad nuxi %d %d%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SBIG:
- if(debug['a'] && i == 0) {
- Bprint(&bso, "\t%P\n", curp);
+ else{
+ if(p->from.sym->foreign){ // 4 bytes of THUMB first
+ if(lastt < 0)
+ lastt = pc;
+ pc += 4;
}
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.sbig[i];
- l++;
+ if(lastt >= 0){
+ outt(lastt, pc-1);
+ lastt = -1;
}
- break;
}
+ if(cursym->next == nil)
+ for(; p != P; p = p->link)
+ pc = p->pc = INITTEXT;
}
- write(cout, buf.dbuf, n);
+ if(lastt >= 0)
+ outt(lastt, pc+1);
}
void
-asmout(Prog *p, Optab *o)
+asmout(Prog *p, Optab *o, int32 *out)
{
int32 o1, o2, o3, o4, o5, o6, v;
int r, rf, rt, rt2;
- Sym *s;
+ Reloc *rel;
PP = p;
o1 = 0;
@@ -1416,7 +773,7 @@ PP = p;
o5 = 0;
o6 = 0;
armsize += o->size;
-if(debug['P']) print("%ulx: %P type %d\n", (uint32)(p->pc), p, o->type);
+if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
switch(o->type) {
default:
diag("unknown asm %d", o->type);
@@ -1424,7 +781,7 @@ if(debug['P']) print("%ulx: %P type %d\n", (uint32)(p->pc), p, o->type);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used);
+if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
break;
case 1: /* op R,[R],R */
@@ -1485,14 +842,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
case 5: /* bra s */
v = -8;
- if(p->cond == UP) {
- s = p->to.sym;
- if(s->type != SUNDEF)
- diag("bad branch sym type");
- v = (uint32)s->value >> (Roffset-2);
- dynreloc(s, p->pc, 0);
- }
- else if(p->cond != P)
+ if(p->cond != P)
v = (p->cond->pc - pc) - 8;
#ifdef CALLEEBX
if(p->as == ABL)
@@ -1553,18 +903,17 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 11: /* word */
- switch(aclass(&p->to)) {
- case C_LCON:
- if(!dlm)
- break;
- if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
- break;
- case C_ADDR:
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, p->to.offset);
- dynreloc(p->to.sym, p->pc, 1);
- }
+ aclass(&p->to);
o1 = instoffset;
+ if(p->to.sym != S) {
+ rel = addrel(cursym);
+ rel->off = pc - cursym->value;
+ rel->siz = 4;
+ rel->type = D_ADDR;
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+ o1 = 0;
+ }
break;
case 12: /* movw $lcon, reg */
@@ -1890,38 +1239,15 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
case 54: /* floating point arith */
o1 = oprrr(p->as, p->scond);
- if(p->from.type == D_FCONST) {
- rf = chipfloat(p->from.ieee);
- if(rf < 0){
- diag("invalid floating-point immediate\n%P", p);
- rf = 0;
- }
- rf |= (1<<3);
- } else
- rf = p->from.reg;
+ rf = p->from.reg;
rt = p->to.reg;
r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0; /* CMP[FD] */
- else if(o1 & (1<<15))
- r = 0; /* monadic */
- else if(r == NREG)
+ if(r == NREG) {
r = rt;
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 55: /* floating point fix and float */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- if(p->to.type == D_NONE){
- rt = 0;
- diag("to.type==D_NONE (asm/fp)");
+ if(p->as == AMOVF || p->as == AMOVD)
+ r = 0;
}
- if(p->from.type == D_REG)
- o1 |= (rf<<12) | (rt<<16);
- else
- o1 |= rf | (rt<<12);
+ o1 |= rf | (r<<16) | (rt<<12);
break;
case 56: /* move to FP[CS]R */
@@ -1983,11 +1309,8 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 63: /* bcase */
- if(p->cond != P) {
+ if(p->cond != P)
o1 = p->cond->pc;
- if(dlm)
- dynreloc(S, p->pc, 1);
- }
break;
/* reloc ops */
@@ -2114,7 +1437,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
if(p->to.sym->thumb)
v |= 1; // T bit
o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
- o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
+ o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
o4 = opbra(AB, 14); // B over o6
o5 = v;
@@ -2132,7 +1455,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
o1 |= immrot(instoffset);
o1 |= p->to.reg << 16;
o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
break;
case 76: /* bx O(R) when returning from fn*/
@@ -2164,35 +1487,114 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
o1 |= p->to.reg << 12;
o1 |= (p->scond & C_SCOND) << 28;
break;
+ case 80: /* fmov zfcon,freg */
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ diag("floating point cannot be conditional"); // cant happen
+ o1 = 0xf3000110; // EOR 64
+
+ // always clears the double float register
+ r = p->to.reg;
+ o1 |= r << 0;
+ o1 |= r << 12;
+ o1 |= r << 16;
+ break;
+ case 81: /* fmov sfcon,freg */
+ o1 = 0x0eb00a00; // VMOV imm 32
+ if(p->as == AMOVD)
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= p->to.reg << 12;
+ v = chipfloat(&p->from.ieee);
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+ break;
+ case 82: /* fcmp freg,freg, */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->reg<<12) | (p->from.reg<<0);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 83: /* fcmp freg,, */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<12) | (1<<16);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 84: /* movfw freg,freg - truncate float-to-fix */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 85: /* movwf freg,freg - fix-to-float */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 86: /* movfw freg,reg - truncate float-to-fix */
+ // macro for movfw freg,FTMP; movw FTMP,reg
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (FREGTMP<<12);
+ o2 = oprrr(AMOVFW+AEND, p->scond);
+ o2 |= (FREGTMP<<16);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 87: /* movwf reg,freg - fix-to-float */
+ // macro for movw reg,FTMP; movwf FTMP,freg
+ o1 = oprrr(AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (FREGTMP<<16);
+ o2 = oprrr(p->as, p->scond);
+ o2 |= (FREGTMP<<0);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 88: /* movw reg,freg */
+ o1 = oprrr(AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (p->to.reg<<16);
+ break;
+ case 89: /* movw freg,reg */
+ o1 = oprrr(AMOVFW+AEND, p->scond);
+ o1 |= (p->from.reg<<16);
+ o1 |= (p->to.reg<<12);
+ break;
}
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ out[5] = o6;
+ return;
v = p->pc;
switch(o->size) {
default:
if(debug['a'])
- Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
break;
case 4:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
lputl(o1);
break;
case 8:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
lputl(o1);
lputl(o2);
break;
case 12:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
lputl(o1);
lputl(o2);
lputl(o3);
break;
case 16:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, p);
lputl(o1);
lputl(o2);
@@ -2201,7 +1603,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 20:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, o5, p);
lputl(o1);
lputl(o2);
@@ -2211,7 +1613,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 24:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, o5, o6, p);
lputl(o1);
lputl(o2);
@@ -2262,26 +1664,51 @@ oprrr(int a, int sc)
case ASRA: return o | (0xd<<21) | (2<<5);
case ASWI: return o | (0xf<<24);
- case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
- case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8);
- case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
- case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8);
- case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
- case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8);
- case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
- case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8);
- case ACMPD:
- case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */
-
- case AMOVF:
- case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
- case AMOVD:
- case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
-
- case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
- case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
- case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
- case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
+ case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
+ case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
+ case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
+ case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
+ case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
+ case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
+ case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
+ case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
+ case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
+
+ case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
+ case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
+
+ case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (1<<8); // dtof
+ case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (0<<8); // dtof
+
+ case AMOVWF:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<8); // toint, double
+ case AMOVWD:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (1<<8); // toint, double
+
+ case AMOVFW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
+ case AMOVDW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
+
+ case AMOVWF+AEND: // copy WtoF
+ 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);
}
diag("bad rrr %d", a);
prasm(curp);
@@ -2337,12 +1764,13 @@ olr(int32 v, int b, int r, int sc)
o |= 1 << 23;
if(sc & C_WBIT)
o |= 1 << 21;
- o |= (0x1<<26) | (1<<20);
+ o |= (1<<26) | (1<<20);
if(v < 0) {
+ if(sc & C_UBIT) diag(".U on neg offset");
v = -v;
o ^= 1 << 23;
}
- if(v >= (1<<12))
+ if(v >= (1<<12) || v < 0)
diag("literal span too large: %d (R%d)\n%P", v, b, PP);
o |= v;
o |= b << 16;
@@ -2367,7 +1795,7 @@ olhr(int32 v, int b, int r, int sc)
v = -v;
o ^= 1 << 23;
}
- if(v >= (1<<8))
+ if(v >= (1<<8) || v < 0)
diag("literal span too large: %d (R%d)\n%P", v, b, PP);
o |= (v&0xf)|((v>>4)<<8)|(1<<22);
o |= b << 16;
@@ -2434,25 +1862,25 @@ ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
o |= 1 << 24;
if(sc & C_WBIT)
o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23);
+ o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
if(v < 0) {
v = -v;
o ^= 1 << 23;
}
if(v & 3)
diag("odd offset for floating point op: %d\n%P", v, p);
- else if(v >= (1<<10))
+ else
+ if(v >= (1<<10) || v < 0)
diag("literal span too large: %d\n%P", v, p);
o |= (v>>2) & 0xFF;
o |= b << 16;
o |= r << 12;
- o |= 1 << 8;
switch(a) {
default:
diag("bad fst %A", a);
case AMOVD:
- o |= 1<<15;
+ o |= 1 << 8;
case AMOVF:
break;
}
@@ -2481,28 +1909,104 @@ omvl(Prog *p, Adr *a, int dr)
return o1;
}
-static Ieee chipfloats[] = {
- {0x00000000, 0x00000000}, /* 0 */
- {0x00000000, 0x3ff00000}, /* 1 */
- {0x00000000, 0x40000000}, /* 2 */
- {0x00000000, 0x40080000}, /* 3 */
- {0x00000000, 0x40100000}, /* 4 */
- {0x00000000, 0x40140000}, /* 5 */
- {0x00000000, 0x3fe00000}, /* .5 */
- {0x00000000, 0x40240000}, /* 10 */
-};
+int
+chipzero(Ieee *e)
+{
+ if(e->l != 0 || e->h != 0)
+ return -1;
+ return 0;
+}
int
chipfloat(Ieee *e)
{
- Ieee *p;
int n;
+ ulong h;
- for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
- p = &chipfloats[n];
- if(p->l == e->l && p->h == e->h)
- return n;
- }
+ if(e->l != 0 || (e->h&0xffff) != 0)
+ goto no;
+ h = e->h & 0x7fc00000;
+ if(h != 0x40000000 && h != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(e->h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (e->h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
+ return n;
+
+no:
return -1;
}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
+ continue;
+
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
+ continue;
+
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
+ }
+ }
+ }
+
+ for(s = textp; s != nil; s = s->next) {
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
index b09995d71..6f7408116 100644
--- a/src/cmd/5l/doc.go
+++ b/src/cmd/5l/doc.go
@@ -20,8 +20,8 @@ Original options are listed in the link above.
Options new in this version:
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_arm.
-r dir1:dir2:...
Set the dynamic linker search path when using ELF.
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index c6659cfab..4e7ccea88 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -45,20 +45,21 @@ enum
/* do not undefine this - code will be removed eventually */
#define CALLEEBX
+#define dynptrsize 0
+
typedef struct Adr Adr;
typedef struct Sym Sym;
typedef struct Autom Auto;
typedef struct Prog Prog;
+typedef struct Reloc Reloc;
typedef struct Optab Optab;
typedef struct Oprang Oprang;
typedef uchar Opcross[32][2][32];
typedef struct Count Count;
-typedef struct Use Use;
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define U ((Use*)0)
-#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
struct Adr
{
@@ -66,14 +67,10 @@ struct Adr
{
int32 u0offset;
char* u0sval;
- Ieee* u0ieee;
+ Ieee u0ieee;
char* u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
char type;
uchar index; // not used on arm, required by ld/go.c
char reg;
@@ -85,11 +82,18 @@ struct Adr
#define offset u0.u0offset
#define sval u0.u0sval
+#define scon sval
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int16 type;
+ int32 add;
+ Sym* sym;
+};
struct Prog
{
@@ -112,35 +116,51 @@ struct Prog
uchar reg;
uchar align;
};
+
#define regused u0.u0regused
#define forwd u0.u0forwd
+#define datasize reg
+#define textflag reg
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar leaf;
+ int32 dynid;
+ int32 plt;
+ int32 got;
int32 value;
int32 sig;
int32 size;
- uchar used;
+ uchar special;
uchar thumb; // thumb code
uchar foreign; // called by arm if thumb, by thumb if arm
uchar fnptr; // used as fn ptr
- Use* use;
- Sym* link;
- Prog* text;
- Prog* data;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
#define SIGNINTERN (1729*325*1729)
@@ -174,34 +194,24 @@ struct Count
int32 count;
int32 outof;
};
-struct Use
-{
- Prog* p; /* use */
- Prog* ct; /* curtext */
- Use* link;
-};
enum
{
Sxxx,
-
+
+ /* order here is order in output file */
STEXT = 1,
+ SRODATA,
+ SELFDATA,
SDATA,
SBSS,
- SDATA1,
+
SXREF,
- SLEAF,
SFILE,
SCONST,
- SSTRING,
- SUNDEF,
- SREMOVED,
+ SDYNIMPORT,
- SIMPORT,
- SEXPORT,
-
- SFIXED,
- SELFDATA,
+ SSUB = 1<<8,
LFROM = 1<<0,
LTO = 1<<1,
@@ -221,7 +231,9 @@ enum
C_SCON, /* 0xffff */
C_BCON, /* thumb */
C_LCON,
- C_FCON,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
C_GCON, /* thumb */
C_RACON,
@@ -229,9 +241,6 @@ enum
C_LACON,
C_GACON, /* thumb */
- C_RECON,
- C_LECON,
-
C_SBRA,
C_LBRA,
C_GBRA, /* thumb */
@@ -242,12 +251,6 @@ enum
C_SAUTO, /* -0xfff to 0xfff */
C_LAUTO,
- C_HEXT,
- C_FEXT,
- C_HFEXT,
- C_SEXT,
- C_LEXT,
-
C_HOREG,
C_FOREG,
C_HFOREG,
@@ -262,7 +265,7 @@ enum
C_HREG,
C_OFFPC, /* thumb */
- C_ADDR, /* relocatable address */
+ C_ADDR, /* reference to relocatable address */
C_GOK,
@@ -271,7 +274,6 @@ enum
LABEL = 1<<1,
LEAF = 1<<2,
- BIG = (1<<12)-4,
STRINGSZ = 200,
NHASH = 10007,
NHUNK = 100000,
@@ -279,9 +281,7 @@ enum
NENT = 100,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
+ MINLC = 4,
};
EXTERN union
@@ -310,23 +310,18 @@ EXTERN int32 INITTEXT; /* text location */
EXTERN char* INITENTRY; /* entry point */
EXTERN int32 autosize;
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int cbc;
EXTERN uchar* cbp;
EXTERN int cout;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN int32 datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN int32 elfdatsize;
EXTERN char debug[128];
-EXTERN Prog* edatap;
-EXTERN Prog* etextp;
-EXTERN Prog* firstp;
+EXTERN Sym* etextp;
EXTERN char* noname;
-EXTERN int xrefresolv;
EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN char literal[32];
@@ -341,7 +336,7 @@ EXTERN uchar repop[ALAST];
EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
-EXTERN Prog* textp;
+EXTERN Sym* textp;
EXTERN int32 textsize;
EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
@@ -352,14 +347,6 @@ EXTERN int thumb;
EXTERN int seenthumb;
EXTERN int armsize;
-EXTERN int doexp, dlm;
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
-
-#define UP (&undefp)
-
extern char* anames[];
extern Optab optab[];
extern Optab thumboptab[];
@@ -384,6 +371,7 @@ EXTERN Prog* prog_modu;
int Aconv(Fmt*);
int Cconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Nconv(Fmt*);
int Oconv(Fmt*);
int Pconv(Fmt*);
@@ -393,36 +381,29 @@ int thumbaclass(Adr*, Prog*);
void addhist(int32, int);
Prog* appendp(Prog*);
void asmb(void);
-void asmdyn(void);
-void asmlc(void);
void asmthumbmap(void);
-void asmout(Prog*, Optab*);
+void asmout(Prog*, Optab*, int32*);
void thumbasmout(Prog*, Optab*);
-void asmsym(void);
int32 atolwhex(char*);
Prog* brloop(Prog*);
void buildop(void);
void thumbbuildop(void);
void buildrep(int, int);
void cflush(void);
-void ckoff(Sym*, int32);
+int chipzero(Ieee*);
int chipfloat(Ieee*);
int cmp(int, int);
int compound(Prog*);
double cputime(void);
-void datblk(int32, int32, int);
void diag(char*, ...);
void divsig(void);
void dodata(void);
void doprof1(void);
void doprof2(void);
-void dynreloc(Sym*, int32, int);
int32 entryvalue(void);
void exchange(Prog*);
-void export(void);
void follow(void);
void hputl(int);
-void import(void);
int isnop(Prog*);
void listinit(void);
Sym* lookup(char*, int);
@@ -430,10 +411,8 @@ void cput(int);
void hput(int32);
void lput(int32);
void lputl(int32);
-void mkfwd(void);
void* mysbrk(uint32);
void names(void);
-Prog* newdata(Sym *s, int o, int w, int t);
void nocache(Prog*);
int ocmp(const void*, const void*);
int32 opirr(int);
@@ -454,18 +433,17 @@ void prasm(Prog*);
void prepend(Prog*, Prog*);
Prog* prg(void);
int pseudo(Prog*);
-void putsymb(char*, int, int32, int);
int32 regoff(Adr*);
int relinv(int);
int32 rnd(int32, int32);
void softfloat(void);
void span(void);
void strnput(char*, int);
+int32 symaddr(Sym*);
void undef(void);
void wput(int32);
void wputl(ushort w);
void xdefine(char*, int, int32);
-void xfol(Prog*);
void noops(void);
int32 immrot(uint32);
int32 immaddr(int32);
@@ -475,7 +453,6 @@ int isbranch(Prog*);
int fnpinc(Sym *);
int fninc(Sym *);
void thumbcount(void);
-void reachable(void);
void fnptrs(void);
void doelf(void);
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 9cbb5501c..b4df89587 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -42,6 +44,7 @@ listinit(void)
fmtinstall('S', Sconv);
fmtinstall('N', Nconv);
fmtinstall('O', Oconv); // C_type constants
+ fmtinstall('I', Iconv);
}
void
@@ -53,7 +56,6 @@ prasm(Prog *p)
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ], *s;
Prog *p;
int a;
@@ -62,42 +64,41 @@ Pconv(Fmt *fp)
a = p->as;
switch(a) {
default:
- s = str;
- s += sprint(s, "(%d)", p->line);
+ fmtprint(fp, "(%d)", p->line);
if(p->reg == NREG)
- sprint(s, " %A%C %D,%D",
+ fmtprint(fp, " %A%C %D,%D",
a, p->scond, &p->from, &p->to);
else
if(p->from.type != D_FREG)
- sprint(s, " %A%C %D,R%d,%D",
+ fmtprint(fp, " %A%C %D,R%d,%D",
a, p->scond, &p->from, p->reg, &p->to);
else
- sprint(s, " %A%C %D,F%d,%D",
+ fmtprint(fp, " %A%C %D,F%d,%D",
a, p->scond, &p->from, p->reg, &p->to);
break;
case ASWPW:
case ASWPBU:
- sprint(str, "(%d) %A%C R%d,%D,%D",
+ fmtprint(fp, "(%d) %A%C R%d,%D,%D",
p->line, a, p->scond, p->reg, &p->from, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- sprint(str, "(%d) %A%C %D/%d,%D",
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A%C %D/%d,%D",
p->line, a, p->scond, &p->from, p->reg, &p->to);
break;
case AWORD:
- sprint(str, "WORD %x", p->to.offset);
+ fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
break;
case ADWORD:
- sprint(str, "DWORD %x %x", p->from.offset, p->to.offset);
+ fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
break;
}
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -164,98 +165,98 @@ Dconv(Fmt *fp)
switch(a->type) {
default:
- sprint(str, "GOK-type(%d)", a->type);
+ snprint(str, sizeof str, "GOK-type(%d)", a->type);
break;
case D_NONE:
str[0] = 0;
if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
break;
case D_CONST:
if(a->reg == NREG)
- sprint(str, "$%N", a);
+ snprint(str, sizeof str, "$%N", a);
else
- sprint(str, "$%N(R%d)", a, a->reg);
+ snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
break;
case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
break;
case D_SHIFT:
v = a->offset;
op = "<<>>->@>" + (((v>>5) & 3) << 1);
if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
+ seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
break;
case D_OCONST:
- sprint(str, "$*$%N", a);
+ snprint(str, sizeof str, "$*$%N", a);
if(a->reg != NREG)
- sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
break;
case D_OREG:
if(a->reg != NREG)
- sprint(str, "%N(R%d)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)", a, a->reg);
else
- sprint(str, "%N", a);
+ snprint(str, sizeof str, "%N", a);
break;
case D_REG:
- sprint(str, "R%d", a->reg);
+ snprint(str, sizeof str, "R%d", a->reg);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_REGREG:
- sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
+ snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_FREG:
- sprint(str, "F%d", a->reg);
+ snprint(str, sizeof str, "F%d", a->reg);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_PSR:
switch(a->reg) {
case 0:
- sprint(str, "CPSR");
+ snprint(str, sizeof str, "CPSR");
break;
case 1:
- sprint(str, "SPSR");
+ snprint(str, sizeof str, "SPSR");
break;
default:
- sprint(str, "PSR%d", a->reg);
+ snprint(str, sizeof str, "PSR%d", a->reg);
break;
}
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(PSR%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
break;
case D_FPCR:
switch(a->reg){
case 0:
- sprint(str, "FPSR");
+ snprint(str, sizeof str, "FPSR");
break;
case 1:
- sprint(str, "FPCR");
+ snprint(str, sizeof str, "FPCR");
break;
default:
- sprint(str, "FCR%d", a->reg);
+ snprint(str, sizeof str, "FCR%d", a->reg);
break;
}
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(FCR%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
break;
@@ -263,22 +264,22 @@ Dconv(Fmt *fp)
if(curp->cond != P) {
v = curp->cond->pc;
if(a->sym != S)
- sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
else
- sprint(str, "%.5lux(BRANCH)", v);
+ snprint(str, sizeof str, "%.5ux(BRANCH)", v);
} else
if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
+ snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
else
- sprint(str, "%d(APC)", a->offset);
+ snprint(str, sizeof str, "%d(APC)", a->offset);
break;
case D_FCONST:
- sprint(str, "$%e", ieeedtod(a->ieee));
+ snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
break;
case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
+ snprint(str, sizeof str, "$\"%S\"", a->sval);
break;
}
return fmtstrcpy(fp, str);
@@ -374,15 +375,45 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uint32 *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uint32*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n/4; i++) {
+ if(i > 0)
+ fmtprint(&fmt, " ");
+ fmtprint(&fmt, "%.8ux", *p++);
+ }
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
static char*
cnames[] =
{
[C_ADDR] = "C_ADDR",
[C_BCON] = "C_BCON",
[C_FAUTO] = "C_FAUTO",
- [C_FCON] = "C_FCON",
+ [C_ZFCON] = "C_SFCON",
+ [C_SFCON] = "C_SFCON",
+ [C_LFCON] = "C_LFCON",
[C_FCR] = "C_FCR",
- [C_FEXT] = "C_FEXT",
[C_FOREG] = "C_FOREG",
[C_FREG] = "C_FREG",
[C_GACON] = "C_GACON",
@@ -391,9 +422,7 @@ cnames[] =
[C_GOK] = "C_GOK",
[C_GOREG] = "C_GOREG",
[C_HAUTO] = "C_HAUTO",
- [C_HEXT] = "C_HEXT",
[C_HFAUTO] = "C_HFAUTO",
- [C_HFEXT] = "C_HFEXT",
[C_HFOREG] = "C_HFOREG",
[C_HOREG] = "C_HOREG",
[C_HREG] = "C_HREG",
@@ -401,8 +430,6 @@ cnames[] =
[C_LAUTO] = "C_LAUTO",
[C_LBRA] = "C_LBRA",
[C_LCON] = "C_LCON",
- [C_LECON] = "C_LECON",
- [C_LEXT] = "C_LEXT",
[C_LOREG] = "C_LOREG",
[C_NCON] = "C_NCON",
[C_NONE] = "C_NONE",
@@ -411,7 +438,6 @@ cnames[] =
[C_PSR] = "C_PSR",
[C_RACON] = "C_RACON",
[C_RCON] = "C_RCON",
- [C_RECON] = "C_RECON",
[C_REG] = "C_REG",
[C_REGREG] = "C_REGREG",
[C_ROREG] = "C_ROREG",
@@ -419,7 +445,6 @@ cnames[] =
[C_SAUTO] = "C_SAUTO",
[C_SBRA] = "C_SBRA",
[C_SCON] = "C_SCON",
- [C_SEXT] = "C_SEXT",
[C_SHIFT] = "C_SHIFT",
[C_SOREG] = "C_SOREG",
[C_SP] = "C_SP",
@@ -443,19 +468,22 @@ Oconv(Fmt *fp)
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
- if(nerrors > 10) {
+ if(nerrors > 20) {
print("too many errors\n");
errorexit();
}
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 41d235a09..5def0d3f1 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -28,12 +28,16 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code transformations.
+
#include "l.h"
+#include "../ld/lib.h"
// see ../../runtime/proc.c:/StackGuard
enum
{
StackBig = 4096,
+ StackSmall = 128,
};
static Sym* sym_div;
@@ -110,14 +114,12 @@ void
noops(void)
{
Prog *p, *q, *q1, *q2;
- int o, curframe, curbecome, maxbecome, foreign;
+ int o, foreign;
Prog *pmorestack;
Sym *symmorestack;
/*
* find leaf subroutines
- * become sizes
- * frame sizes
* strip NOPs
* expand RET
* expand BECOME pseudo
@@ -127,780 +129,662 @@ noops(void)
Bprint(&bso, "%5.2f noops\n", cputime());
Bflush(&bso);
- pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
-
- if(symmorestack->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symmorestack) {
- pmorestack = p;
- p->reg |= NOSPLIT;
- break;
- }
- }
+ if(symmorestack->type != STEXT) {
+ diag("runtime·morestack not defined");
+ errorexit();
}
- // TODO(kaib): make lack of morestack an error
-// if(pmorestack == P)
-// diag("runtime·morestack not defined");
-
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
+ pmorestack = symmorestack->text;
+ pmorestack->reg |= NOSPLIT;
q = P;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == D_OREG && p->to.reg == REGSP)
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- p->mark |= LEAF;
- curtext = p;
- break;
-
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- q = p;
- if(prog_div == P)
- initdiv();
- if(curtext != P)
- curtext->mark &= ~LEAF;
- setdiv(p->as);
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- q1->mark |= p->mark;
- continue;
-
- case ABL:
- case ABX:
- if(curtext != P)
- curtext->mark &= ~LEAF;
-
- case ABCASE:
- case AB:
-
- case ABEQ:
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
-
- q1 = p->cond;
- if(q1 != P) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->cond = q1;
- }
- }
- break;
- }
- q = p;
- }
-
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ABL:
- // case ABX:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- o = maxbecome - curtext->from.sym->frame;
- if(o <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += o;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, o);
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+
+ switch(p->as) {
+ case ATEXT:
+ p->mark |= LEAF;
+ break;
+
+ case ARET:
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ q = p;
+ if(prog_div == P)
+ initdiv();
+ cursym->text->mark &= ~LEAF;
+ setdiv(p->as);
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ if(q1 != P)
+ q1->mark |= p->mark;
+ continue;
+
+ case ABL:
+ case ABX:
+ cursym->text->mark &= ~LEAF;
+
+ case ABCASE:
+ case AB:
+
+ case ABEQ:
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
}
}
+ break;
}
- break;
+ q = p;
}
}
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- o = p->as;
- switch(o) {
- case ATEXT:
- curtext = p;
- autosize = p->to.offset + 4;
- if(autosize <= 4)
- if(curtext->mark & LEAF) {
- p->to.offset = -4;
- autosize = 0;
- }
-
- if(!autosize && !(curtext->mark & LEAF)) {
- if(debug['v'])
- Bprint(&bso, "save suppressed in: %s\n",
- curtext->from.sym->name);
- Bflush(&bso);
- curtext->mark |= LEAF;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(cursym->text->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ if(!autosize && !(cursym->text->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(&bso);
+ cursym->text->mark |= LEAF;
+ }
#ifdef CALLEEBX
- if(p->from.sym->foreign){
- if(thumb)
- // don't allow literal pool to seperate these
- p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
- // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
- else
- p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
- }
+ if(p->from.sym->foreign){
+ if(thumb)
+ // don't allow literal pool to seperate these
+ p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
+ // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
+ else
+ p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
+ }
#endif
- if(curtext->mark & LEAF) {
- if(curtext->from.sym)
- curtext->from.sym->type = SLEAF;
- if(!autosize)
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ if(!autosize)
+ break;
+ }
+
+ if(thumb){
+ if(!(p->reg & NOSPLIT))
+ diag("stack splitting not supported in thumb");
+ if(!(cursym->text->mark & LEAF)){
+ q = movrr(nil, REGLINK, REGTMPT-1, p);
+ p->link = q;
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT-1;
+ q1->to.type = D_OREG;
+ q1->to.name = D_NONE;
+ q1->to.reg = REGSP;
+ q1->to.offset = 0;
+ q1->link = q->link;
+ q->link = q1;
+ }
+ if(autosize){
+ q2 = prg();
+ q2->as = ASUB;
+ q2->line = p->line;
+ q2->from.type = D_CONST;
+ q2->from.offset = autosize;
+ q2->to.type = D_REG;
+ q2->to.reg = REGSP;
+ q2->link = p->link;
+ p->link = q2;
+ }
break;
- }
-
- if(thumb){
- if(!(p->reg & NOSPLIT))
- diag("stack splitting not supported in thumb");
- if(!(curtext->mark & LEAF)){
- q = movrr(nil, REGLINK, REGTMPT-1, p);
- p->link = q;
+ }
+
+ if(p->reg & NOSPLIT) {
q1 = prg();
q1->as = AMOVW;
+ q1->scond |= C_WBIT;
q1->line = p->line;
q1->from.type = D_REG;
- q1->from.reg = REGTMPT-1;
+ q1->from.reg = REGLINK;
q1->to.type = D_OREG;
- q1->to.name = D_NONE;
+ q1->to.offset = -autosize;
q1->to.reg = REGSP;
- q1->to.offset = 0;
- q1->link = q->link;
- q->link = q1;
- }
- if(autosize){
- q2 = prg();
- q2->as = ASUB;
- q2->line = p->line;
- q2->from.type = D_CONST;
- q2->from.offset = autosize;
- q2->to.type = D_REG;
- q2->to.reg = REGSP;
- q2->link = p->link;
- p->link = q2;
+ q1->link = p->link;
+ p->link = q1;
+ } else if (autosize < StackBig) {
+ // split stack check for small functions
+ // MOVW g_stackguard(g), R1
+ // CMP R1, $-autosize(SP)
+ // MOVW.LO $autosize, R1
+ // MOVW.LO $args, R2
+ // MOVW.LO R14, R3
+ // BL.LO runtime.morestack(SB) // modifies LR
+ // MOVW.W R14,$-autosize(SP)
+
+ // TODO(kaib): add more trampolines
+ // TODO(kaib): put stackguard in register
+ // TODO(kaib): add support for -K and underflow detection
+
+ // MOVW g_stackguard(g), R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ if(autosize < StackSmall) {
+ // CMP R1, SP
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = REGSP;
+ } else {
+ // MOVW $-autosize(SP), R2
+ // CMP R1, R2
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = -autosize;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ 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;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LO $args +4, R2
+ // also need to store the extra 4 bytes.
+ 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->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW.LO R14, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LO;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL.LO runtime.morestack(SB) // modifies LR
+ p = appendp(p);
+ p->as = ABL;
+ p->scond = C_SCOND_LO;
+ p->to.type = D_BRANCH;
+ p->to.sym = symmorestack;
+ p->cond = pmorestack;
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
+ } else { // > StackBig
+ // MOVW $autosize, R1
+ // MOVW $args, R2
+ // MOVW R14, R3
+ // BL runtime.morestack(SB) // modifies LR
+ // MOVW.W R14,$-autosize(SP)
+
+ // MOVW $autosize, R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW $args +4, 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->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW R14, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL runtime.morestack(SB) // modifies LR
+ p = appendp(p);
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symmorestack;
+ p->cond = pmorestack;
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
}
break;
- }
-
- if(p->reg & NOSPLIT) {
- q1 = prg();
- q1->as = AMOVW;
- q1->scond |= C_WBIT;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGLINK;
- q1->to.type = D_OREG;
- q1->to.offset = -autosize;
- q1->to.reg = REGSP;
- q1->link = p->link;
- p->link = q1;
- } else if (autosize < StackBig) {
- // split stack check for small functions
- // MOVW g_stackguard(g), R1
- // CMP R1, $-autosize(SP)
- // MOVW.LO $autosize, R1
- // MOVW.LO $args, R2
- // MOVW.LO R14, R3
- // BL.LO runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // TODO(kaib): add more trampolines
- // TODO(kaib): put stackguard in register
- // TODO(kaib): add support for -K and underflow detection
-
- // MOVW g_stackguard(g), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // CMP R1, $-autosize(SP)
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->from.offset = -autosize;
- p->reg = REGSP;
-
- // MOVW.LO $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LO $args +4, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = ((curtext->to.offset2 + 3) & ~3) + 4;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LO R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL.LO runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LO;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- } else { // > StackBig
- // MOVW $autosize, R1
- // MOVW $args, R2
- // MOVW R14, R3
- // BL runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // MOVW $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $args +4, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = ((curtext->to.offset2 + 3) & ~3) + 4;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- }
- break;
-
- case ARET:
- nocache(p);
- foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr);
-// print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr);
- if(p->from.type == D_CONST)
- goto become;
- if(curtext->mark & LEAF) {
- if(!autosize) {
- if(thumb){
- p = fnret(p, REGLINK, foreign, p);
+
+ case ARET:
+ nocache(p);
+ foreign = seenthumb && (cursym->foreign || cursym->fnptr);
+// print("%s %d %d\n", cursym->name, cursym->foreign, cursym->fnptr);
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ if(thumb){
+ p = fnret(p, REGLINK, foreign, p);
+ break;
+ }
+// if(foreign) print("ABXRET 1 %s\n", cursym->name);
+ p->as = foreign ? ABXRET : AB;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
break;
}
-// if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name);
- p->as = foreign ? ABXRET : AB;
- p->from = zprg.from;
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- break;
}
- }
- if(thumb){
- if(curtext->mark & LEAF){
- if(autosize){
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
+ if(thumb){
+ if(cursym->text->mark & LEAF){
+ if(autosize){
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ q = nil;
+ }
+ else
+ q = p;
+ q = fnret(q, REGLINK, foreign, p);
+ if(q != p)
+ p->link = q;
+ }
+ else{
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_NONE;
+ p->from.reg = REGSP;
+ p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGSP;
- q = nil;
+ p->to.reg = REGTMPT-1;
+ if(autosize){
+ q = prg();
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ }
+ else
+ q = p;
+ q1 = fnret(nil, REGTMPT-1, foreign, p);
+ q1->link = q->link;
+ q->link = q1;
}
- else
- q = p;
- q = fnret(q, REGLINK, foreign, p);
- if(q != p)
- p->link = q;
+ break;
}
- else{
+ if(foreign) {
+// if(foreign) print("ABXRET 3 %s\n", cursym->name);
+#define R 1
p->as = AMOVW;
p->from.type = D_OREG;
p->from.name = D_NONE;
p->from.reg = REGSP;
p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- if(autosize){
- q = prg();
- q->as = AADD;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- }
- else
- q = p;
- q1 = fnret(nil, REGTMPT-1, foreign, p);
+ p->to.reg = R;
+ q = prg();
+ q->as = AADD;
+ q->scond = p->scond;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ q1 = prg();
+ q1->as = ABXRET;
+ q1->scond = p->scond;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = R;
q1->link = q->link;
q->link = q1;
+#undef R
+ }
+ else {
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
}
break;
- }
- if(foreign) {
-// if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name);
-#define R 1
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ if(debug['M'])
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = R;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
q = prg();
- q->as = AADD;
- q->scond = p->scond;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
q->link = p->link;
p->link = q;
- q1 = prg();
- q1->as = ABXRET;
- q1->scond = p->scond;
- q1->line = p->line;
- q1->to.type = D_OREG;
- q1->to.offset = 0;
- q1->to.reg = R;
- q1->link = q->link;
- q->link = q1;
-#undef R
- }
- else {
+ p = q;
+
p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- break;
-
- become:
- if(foreign){
- diag("foreign become - help");
- break;
- }
- if(thumb){
- diag("thumb become - help");
- break;
- }
- print("arm become\n");
- if(curtext->mark & LEAF) {
-
- if(!autosize) {
- p->as = AB;
- p->from = zprg.from;
+ p->to.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+#ifdef CALLEEBX
+ p->as = ABL;
+#else
+ if(prog_div->from.sym->thumb)
+ p->as = thumb ? ABL : ABX;
+ else
+ p->as = thumb ? ABX : ABL;
+#endif
+ p->line = q1->line;
+ p->to.type = D_BRANCH;
+ p->cond = p;
+ switch(o) {
+ case ADIV:
+ p->cond = prog_div;
+ p->to.sym = sym_div;
+ break;
+ case ADIVU:
+ p->cond = prog_divu;
+ p->to.sym = sym_divu;
+ break;
+ case AMOD:
+ p->cond = prog_mod;
+ p->to.sym = sym_mod;
+ break;
+ case AMODU:
+ p->cond = prog_modu;
+ p->to.sym = sym_modu;
break;
}
- }
- q = prg();
- q->scond = p->scond;
- q->line = p->line;
- q->as = AB;
- q->from = zprg.from;
- q->to = p->to;
- q->cond = p->cond;
- q->link = p->link;
- p->link = q;
- if(thumb){
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_CONST;
- q1->from.offset = autosize;
- q1->to.type = D_REG;
- q1->to.reg = REGSP;
+
+ /* MOV REGTMP, b */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
p->as = AMOVW;
- p->line = p->line;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q1->link = q;
- p->link = q1;
- q2 = movrr(nil, REGTMPT-1, REGLINK, p);
- q2->link = q;
- q1->link = q2;
- break;
- }
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from = zprg.from;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to = zprg.to;
- p->to.type = D_REG;
- p->to.reg = REGLINK;
-
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- if(debug['M'])
- break;
- if(p->from.type != D_REG)
- break;
- if(p->to.type != D_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->from.reg;
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- /* MOV b,REGTMP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->reg;
- if(q1->reg == NREG)
- p->from.reg = q1->to.reg;
- p->to.type = D_REG;
- p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
- p->to.offset = 0;
-
- /* CALL appropriate */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
-#ifdef CALLEEBX
- p->as = ABL;
-#else
- if(prog_div != UP && prog_div->from.sym->thumb)
- p->as = thumb ? ABL : ABX;
- else
- p->as = thumb ? ABX : ABL;
-#endif
- p->line = q1->line;
- p->to.type = D_BRANCH;
- p->cond = p;
- switch(o) {
- case ADIV:
- p->cond = prog_div;
- p->to.sym = sym_div;
- break;
- case ADIVU:
- p->cond = prog_divu;
- p->to.sym = sym_divu;
- break;
- case AMOD:
- p->cond = prog_mod;
- p->to.sym = sym_mod;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ /* SUB $8,SP */
+ q1->as = ASUB;
+ q1->from.type = D_CONST;
+ q1->from.offset = 8;
+ q1->from.reg = NREG;
+ q1->reg = NREG;
+ q1->to.type = D_REG;
+ q1->to.reg = REGSP;
+
break;
- case AMODU:
- p->cond = prog_modu;
- p->to.sym = sym_modu;
+ case AMOVW:
+ if(thumb){
+ Adr *a = &p->from;
+
+ if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
+ diag("SP offset not multiple of 4");
+ }
break;
- }
-
- /* MOV REGTMP, b */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.reg = NREG;
- p->from.offset = 8;
- p->reg = NREG;
- p->to.type = D_REG;
- p->to.reg = REGSP;
-
- /* SUB $8,SP */
- q1->as = ASUB;
- q1->from.type = D_CONST;
- q1->from.offset = 8;
- q1->from.reg = NREG;
- q1->reg = NREG;
- q1->to.type = D_REG;
- q1->to.reg = REGSP;
-
- break;
- case AMOVW:
- if(thumb){
- Adr *a = &p->from;
-
- if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
- diag("SP offset not multiple of 4");
- }
- break;
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- if(thumb){
- if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->from.name == D_AUTO)
- q->from.offset += autosize;
- else if(p->from.name == D_PARAM)
- q->from.offset += autosize+4;
- q->from.name = D_NONE;
- q->from.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ if(thumb){
+ if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->from.name == D_AUTO)
+ q->from.offset += autosize;
+ else if(p->from.name == D_PARAM)
+ q->from.offset += autosize+4;
+ q->from.name = D_NONE;
+ q->from.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ }
+ if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->to.name == D_AUTO)
+ q->to.offset += autosize;
+ else if(p->to.name == D_PARAM)
+ q->to.offset += autosize+4;
+ q->to.name = D_NONE;
+ q->to.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ if(q->to.offset < 0 || q->to.offset > 255){ // complicated
+ p->to.reg = REGTMPT+1; // mov sp, r8
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AMOVW;
+ q1->from.type = D_CONST;
+ q1->from.offset = q->to.offset;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // mov $o, r7
+ p->link = q1;
+ q1->link = q;
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AADD;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT+1;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // add r8, r7
+ p->link->link = q1;
+ q1->link = q;
+ q->to.offset = 0; // mov* r, 0(r7)
+ /* phew */
+ }
+ }
}
- if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->to.name == D_AUTO)
- q->to.offset += autosize;
- else if(p->to.name == D_PARAM)
- q->to.offset += autosize+4;
- q->to.name = D_NONE;
- q->to.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- if(q->to.offset < 0 || q->to.offset > 255){ // complicated
- p->to.reg = REGTMPT+1; // mov sp, r8
- q1 = prg();
- q1->line = p->line;
- q1->as = AMOVW;
- q1->from.type = D_CONST;
- q1->from.offset = q->to.offset;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // mov $o, r7
- p->link = q1;
- q1->link = q;
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT+1;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // add r8, r7
- p->link->link = q1;
- q1->link = q;
- q->to.offset = 0; // mov* r, 0(r7)
- /* phew */
+ break;
+ case AMOVM:
+ if(thumb){
+ if(p->from.type == D_OREG){
+ if(p->from.offset == 0)
+ p->from.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
+ }
+ else if(p->to.type == D_OREG){
+ if(p->to.offset == 0)
+ p->to.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
}
}
- }
- break;
- case AMOVM:
- if(thumb){
- if(p->from.type == D_OREG){
- if(p->from.offset == 0)
+ break;
+ case AB:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = AMOVW;
p->from.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- else if(p->to.type == D_OREG){
- if(p->to.offset == 0)
+ p->from.reg = p->to.reg;
p->to.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- }
- break;
- case AB:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMPT-1;
- q->to.type = D_REG;
- q->to.reg = REGPC;
- q->link = p->link;
- p->link = q;
+ p->to.reg = REGPC;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGTMPT-1;
+ q->to.type = D_REG;
+ q->to.reg = REGPC;
+ q->link = p->link;
+ p->link = q;
+ }
}
- }
- if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
- // print("warn %s: b (R%d) assuming a return\n", curtext->from.sym->name, p->to.reg);
- p->as = ABXRET;
- }
- break;
- case ABL:
- case ABX:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = o;
- p->from.type = D_NONE;
- p->to.type = D_REG;
+ if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
+ // print("warn %s: b (R%d) assuming a return\n", cursym->name, p->to.reg);
+ p->as = ABXRET;
}
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = o;
- q->line = p->line;
- q->from.type = D_NONE;
- q->to.type = D_REG;
- q->to.reg = REGTMPT-1;
- q->link = p->link;
- p->link = q;
+ break;
+ case ABL:
+ case ABX:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = o;
+ p->from.type = D_NONE;
+ p->to.type = D_REG;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = o;
+ q->line = p->line;
+ q->from.type = D_NONE;
+ q->to.type = D_REG;
+ q->to.reg = REGTMPT-1;
+ q->link = p->link;
+ p->link = q;
+ }
}
+ break;
}
- break;
}
}
}
@@ -911,12 +795,9 @@ sigdiv(char *n)
Sym *s;
s = lookup(n, 0);
- if(s->type == STEXT){
+ if(s->type == STEXT)
if(s->sig == 0)
s->sig = SIGNINTERN;
- }
- else if(s->type == 0 || s->type == SXREF)
- s->type = SUNDEF;
}
void
@@ -928,25 +809,10 @@ divsig(void)
sigdiv("_modu");
}
-static void
-sdiv(Sym *s)
-{
- if(s->type == 0 || s->type == SXREF){
- /* undefsym(s); */
- s->type = SXREF;
- if(s->sig == 0)
- s->sig = SIGNINTERN;
- s->subtype = SIMPORT;
- }
- else if(s->type != STEXT)
- diag("undefined: %s", s->name);
-}
-
void
initdiv(void)
{
Sym *s2, *s3, *s4, *s5;
- Prog *p;
if(prog_div != P)
return;
@@ -954,38 +820,25 @@ initdiv(void)
sym_divu = s3 = lookup("_divu", 0);
sym_mod = s4 = lookup("_mod", 0);
sym_modu = s5 = lookup("_modu", 0);
- if(dlm) {
- sdiv(s2); if(s2->type == SXREF) prog_div = UP;
- sdiv(s3); if(s3->type == SXREF) prog_divu = UP;
- sdiv(s4); if(s4->type == SXREF) prog_mod = UP;
- sdiv(s5); if(s5->type == SXREF) prog_modu = UP;
- }
- for(p = firstp; p != P; p = p->link)
- if(p->as == ATEXT) {
- if(p->from.sym == s2)
- prog_div = p;
- if(p->from.sym == s3)
- prog_divu = p;
- if(p->from.sym == s4)
- prog_mod = p;
- if(p->from.sym == s5)
- prog_modu = p;
- }
+ prog_div = s2->text;
+ prog_divu = s3->text;
+ prog_mod = s4->text;
+ prog_modu = s5->text;
if(prog_div == P) {
diag("undefined: %s", s2->name);
- prog_div = curtext;
+ prog_div = cursym->text;
}
if(prog_divu == P) {
diag("undefined: %s", s3->name);
- prog_divu = curtext;
+ prog_divu = cursym->text;
}
if(prog_mod == P) {
diag("undefined: %s", s4->name);
- prog_mod = curtext;
+ prog_mod = cursym->text;
}
if(prog_modu == P) {
diag("undefined: %s", s5->name);
- prog_modu = curtext;
+ prog_modu = cursym->text;
}
}
@@ -1000,7 +853,7 @@ setdiv(int as)
case AMOD: p = prog_mod; break;
case AMODU: p = prog_modu; break;
}
- if(p != UP && thumb != p->from.sym->thumb)
+ if(thumb != p->from.sym->thumb)
p->from.sym->foreign = 1;
}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index e3597e040..cb9ad9805 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
@@ -50,28 +52,6 @@ char *thestring = "arm";
* -H5 -T0xC0008010 -R1024 is ipaq
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else{
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
static char*
linkername[] =
{
@@ -94,7 +74,6 @@ main(int argc, char *argv[])
cout = -1;
listinit();
nerrors = 0;
- curtext = P;
outfile = "5.out";
HEADTYPE = -1;
INITTEXT = -1;
@@ -231,10 +210,10 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
zprg.as = AGOK;
@@ -247,9 +226,6 @@ main(int argc, char *argv[])
buildop();
thumbbuildop(); // could build on demand
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
nuxiinit();
@@ -257,8 +233,6 @@ main(int argc, char *argv[])
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
@@ -268,52 +242,30 @@ main(int argc, char *argv[])
for(i=0; i<nelem(linkername); i++)
mark(lookup(linkername[i], 0));
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- goto out;
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- initdiv();
- import();
- HEADTYPE = 2;
- INITTEXT = INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- else
- divsig();
- export();
+ if(textp == nil) {
+ diag("no code");
+ errorexit();
}
+
patch();
if(debug['p'])
if(debug['1'])
doprof1();
else
doprof2();
- if(debug['u'])
- reachable();
doelf();
- dodata();
- if(seenthumb && debug['f'])
- fnptrs();
follow();
- if(firstp == P) {
- diag("no code");
- errorexit();
- }
softfloat();
noops();
span();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
-out:
if(debug['c']){
thumbcount();
print("ARM size = %d\n", armsize);
@@ -327,7 +279,7 @@ out:
errorexit();
}
-void
+static void
zaddr(Biobuf *f, Adr *a, Sym *h[])
{
int i, c;
@@ -355,7 +307,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
if(a->type == D_CONST || a->type == D_OCONST) {
if(a->name == D_EXTERN || a->name == D_STATIC) {
s = a->sym;
- if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) {
+ if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
if(0 && !s->fnptr && s->name[0] != '.')
print("%s used as function pointer\n", s->name);
s->fnptr = 1; // over the top cos of SXREF
@@ -398,9 +350,8 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
break;
case D_FCONST:
- a->ieee = mal(sizeof(Ieee));
- a->ieee->l = Bget4(f);
- a->ieee->h = Bget4(f);
+ a->ieee.l = Bget4(f);
+ a->ieee.h = Bget4(f);
break;
}
s = a->sym;
@@ -441,7 +392,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
- Prog *p, *t;
+ Prog *p;
Sym *h[NSYM], *s, *di;
int v, o, r, skip;
uint32 sig;
@@ -449,7 +400,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int ntext;
int32 eof;
char src[1024], *x;
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -499,13 +452,17 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, s->file, sig, pn, s->name);
+ diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
}
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h)) {
+ fprint(2, "%s: mangled input file\n", pn);
+ errorexit();
+ }
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -533,8 +490,8 @@ loop:
zaddr(f, &p->from, h);
zaddr(f, &p->to, h);
- if(p->reg > NREG)
- diag("register out of range %d", p->reg);
+ if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
+ diag("register out of range %A %d", p->as, p->reg);
p->link = P;
p->cond = P;
@@ -559,10 +516,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -582,98 +539,31 @@ loop:
s->type = SBSS;
s->value = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->reg & DUPOK)
s->dupok = 1;
break;
- case ADYNT:
- s = p->from.sym;
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->reg = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(s == S)
- break;
-
- p->from.offset = di->value;
- s->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_CONST;
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- }
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- break;
-
- case AINIT:
- s = p->from.sym;
- if(s == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- s->type = SDATA;
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- }
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- break;
-
case ADATA:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
if(debug['v'])
Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
+ savedata(s, p);
+ unmal(p, sizeof *p);
break;
case AGOK:
@@ -683,31 +573,24 @@ loop:
break;
case ATEXT:
- s = p->from.sym;
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- setarch(p);
- setthumb(p);
- p->align = 4;
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
- skip = 0;
- curtext = p;
- autosize = (p->to.offset+3L) & ~3L;
- p->to.offset = autosize;
- autosize += 4;
s = p->from.sym;
if(s == S) {
diag("TEXT must have a name\n%P", p);
errorexit();
}
+ cursym = s;
+ if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
+ /* redefinition, so file has probably been seen before */
+ if(debug['v'])
+ Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ skip = 0;
if(s->type != 0 && s->type != SXREF) {
if(p->reg & DUPOK) {
skip = 1;
@@ -715,21 +598,24 @@ loop:
}
diag("redefinition: %s\n%P", s->name, p);
}
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ setarch(p);
+ setthumb(p);
+ p->align = 4;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
s->type = STEXT;
s->text = p;
s->value = pc;
s->thumb = thumb;
- lastp->link = p;
lastp = p;
p->pc = pc;
pc++;
- if(textp == P) {
- textp = p;
- etextp = p;
- goto loop;
- }
- etextp->cond = p;
- etextp = p;
break;
case ASUB:
@@ -778,27 +664,15 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_OREG;
- t->from.sym = s;
- t->from.name = D_EXTERN;
- t->reg = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
@@ -813,28 +687,17 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
- p->from.ieee->l, p->from.ieee->h);
+ sprint(literal, "$%ux.%ux",
+ p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_OREG;
- t->from.sym = s;
- t->from.name = D_EXTERN;
- t->reg = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
@@ -847,13 +710,17 @@ loop:
casedef:
if(skip)
nopout(p);
-
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ break;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
break;
}
goto loop;
@@ -872,191 +739,13 @@ prg(void)
return p;
}
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->reg = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = n*4 + 4;
- p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = thumb ? REGTMPT : REGTMP;
- p->to.type = D_OREG;
- p->to.name = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.sym = s;
- q->reg = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- ps2 = p;
- p->reg = 1;
- }
- if(p->from.sym == s4) {
- ps4 = p;
- p->reg = 1;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- if(p->reg & NOPROF) {
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * BL profin, R2
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->cond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * BL profout
- */
- p->as = ABL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->cond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
-
static void
puntfp(Prog *p)
{
USED(p);
/* floating point - punt for now */
- curtext->reg = NREG; /* ARM */
- curtext->from.sym->thumb = 0;
+ cursym->text->reg = NREG; /* ARM */
+ cursym->thumb = 0;
thumb = 0;
// print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line);
}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 92fe12fc2..96b216837 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -34,8 +34,6 @@ Optab optab[] =
{
/* struct Optab:
OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
@@ -56,7 +54,6 @@ Optab optab[] =
{ AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
- { AMOVW, C_RECON,C_NONE, C_REG, 4, 4, REGSB },
{ AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
{ AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
@@ -81,7 +78,6 @@ Optab optab[] =
{ AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
{ AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
@@ -109,85 +105,64 @@ Optab optab[] =
{ AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVW, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
{ AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVBU, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
{ AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVB, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVH, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVHU, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVH, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
{ AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
{ AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
- { AMOVHU, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
{ AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
{ AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
- { AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
{ AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
{ AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVBU, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
{ AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
{ AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVB, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVH, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVH, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
{ AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
{ AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
{ AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
{ AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
{ AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
{ AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
- { AMOVW, C_LECON,C_NONE, C_REG, 34, 8, REGSB, LFROM },
{ AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
{ AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
@@ -201,19 +176,15 @@ Optab optab[] =
{ ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_FEXT, 50, 4, REGSB },
{ AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
{ AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
- { AMOVF, C_FEXT, C_NONE, C_FREG, 51, 4, REGSB },
{ AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
{ AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_LEXT, 52, 12, REGSB, LTO },
{ AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
{ AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
- { AMOVF, C_LEXT, C_NONE, C_FREG, 53, 12, REGSB, LFROM },
{ AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
{ AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
@@ -222,17 +193,8 @@ Optab optab[] =
{ AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 },
- { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 },
- { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 },
-
{ AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
{ AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
@@ -248,41 +210,46 @@ Optab optab[] =
{ ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
{ AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
{ AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVHU, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
{ AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
{ AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVB, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVHU, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
{ AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
{ AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
{ AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
{ AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVB, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVH, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
{ ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
{ ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
+ { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 4, 0 },
+ { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
+
+ { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
+ { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
+ { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
+ { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
+
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 06b1792b4..e16b34171 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -28,147 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
-void
-dodata(void)
-{
- int i, t;
- Sym *s;
- Prog *p;
- int32 orig, v;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- v = p->from.offset + p->reg;
- if(v > s->value)
- diag("initialize bounds (%ld/%ld): %s\n%P",
- v, s->value, s->name, p);
- if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){
- s = p->to.sym;
- if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF))
- s->fnptr = 1;
- }
- }
-
- if(debug['t']) {
- /*
- * pull out string constants
- */
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->to.type == D_SCONST)
- s->type = SSTRING;
- }
- }
-
- /*
- * pass 0
- * assign elf data - must be segregated from real data
- */
- orig = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable || s->type != SELFDATA)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->size = v;
- s->value = orig;
- orig += v;
- }
- elfdatsize = orig;
-
- /*
- * pass 1
- * assign 'small' variables to data segment
- * (rational is that data segment is more easily
- * addressed through offset on R12)
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- t = s->type;
- if(t != SDATA && t != SBSS)
- continue;
- v = s->value;
- if(v == 0) {
- diag("%s: no size", s->name);
- v = 1;
- }
- while(v & 3)
- v++;
- s->size = v;
- s->value = v;
- if(v > MINSIZ)
- continue;
- s->value = orig;
- orig += v;
- s->type = SDATA1;
- }
-
- /*
- * pass 2
- * assign large 'data' variables to data segment
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- t = s->type;
- if(t != SDATA) {
- if(t == SDATA1)
- s->type = SDATA;
- continue;
- }
- v = s->value;
- s->size = v;
- s->value = orig;
- orig += v;
- }
-
- while(orig & 7)
- orig++;
- datsize = orig;
-
- /*
- * pass 3
- * everything else to bss segment
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SBSS)
- continue;
- v = s->value;
- s->size = v;
- s->value = orig;
- orig += v;
- }
- while(orig & 7)
- orig++;
- bsssize = orig-datsize;
-
- xdefine("setR12", SDATA, 0L+BIG);
- xdefine("bdata", SDATA, 0L);
- xdefine("data", SBSS, 0);
- xdefine("edata", SDATA, datsize);
- xdefine("end", SBSS, datsize+bsssize);
- xdefine("etext", STEXT, 0L);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
+static void xfol(Prog*, Prog**);
void
undef(void)
@@ -177,7 +42,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
@@ -223,20 +88,23 @@ relinv(int a)
void
follow(void)
{
+ Prog *firstp, *lastp;
+
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
-
- firstp = firstp->link;
- lastp->link = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q, *r;
int a, i;
@@ -246,12 +114,6 @@ loop:
return;
setarch(p);
a = p->as;
- if(a == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->cond;
- goto loop;
- }
if(a == AB) {
q = p->cond;
if(q != P && q->as != ATEXT) {
@@ -263,7 +125,7 @@ loop:
}
if(p->mark & FOLL) {
for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == lastp)
+ if(q == *last || q == nil)
break;
a = q->as;
if(a == ANOP) {
@@ -272,7 +134,7 @@ loop:
}
if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
goto copy;
- if(!q->cond || (q->cond->mark&FOLL))
+ if(q->cond == P || (q->cond->mark&FOLL))
continue;
if(a != ABEQ && a != ABNE)
continue;
@@ -285,12 +147,12 @@ loop:
r->mark |= FOLL;
if(p != q) {
p = p->link;
- lastp->link = r;
- lastp = r;
+ (*last)->link = r;
+ *last = r;
continue;
}
- lastp->link = r;
- lastp = r;
+ (*last)->link = r;
+ *last = r;
if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
return;
r->as = ABNE;
@@ -299,7 +161,7 @@ loop:
r->cond = p->link;
r->link = p->cond;
if(!(r->link->mark&FOLL))
- xfol(r->link);
+ xfol(r->link, last);
if(!(r->cond->mark&FOLL))
print("cant happen 2\n");
return;
@@ -315,8 +177,8 @@ loop:
p = q;
}
p->mark |= FOLL;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
return;
}
@@ -329,7 +191,7 @@ loop:
p->link = p->cond;
p->cond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->cond);
if(q == P)
q = p->cond;
@@ -349,7 +211,7 @@ patch(void)
{
int32 c, vexit;
Prog *p, *q;
- Sym *s, *s1;
+ Sym *s;
int a;
if(debug['v'])
@@ -358,113 +220,71 @@ patch(void)
mkfwd();
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- a = p->as;
- if(a == ATEXT)
- curtext = p;
- if(seenthumb && a == ABL){
- // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
- // print("%s calls %s\n", s1->name, s->name);
- if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb)
- s->foreign = 1;
- }
- if((a == ABL || a == ABX || a == AB || a == ARET) &&
- p->to.type != D_BRANCH && p->to.sym != S) {
- s = p->to.sym;
- switch(s->type) {
- default:
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- p->to.type = D_BRANCH;
- break;
- case SUNDEF:
- if(p->as != ABL)
- diag("help: SUNDEF in AB || ARET");
- p->to.offset = 0;
- p->to.type = D_BRANCH;
- p->cond = UP;
- break;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(seenthumb && a == ABL){
+ // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
+ // print("%s calls %s\n", s1->name, s->name);
+ if((s = p->to.sym) != S && s->thumb != cursym->thumb)
+ s->foreign = 1;
}
- }
- if(p->to.type != D_BRANCH || p->cond == UP)
- continue;
- c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
+ if((a == ABL || a == ABX || a == AB || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ switch(s->type) {
+ default:
+ diag("undefined: %s", s->name);
+ s->type = STEXT;
+ s->value = vexit;
+ continue; // avoid more error messages
+ case STEXT:
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ break;
+ }
+ }
+ if(p->to.type != D_BRANCH)
continue;
+ c = p->to.offset;
+ for(q = textp->text; q != P;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
- if(c == q->pc)
- break;
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range %ld\n%P", c, p);
- p->to.type = D_NONE;
+ if(q == P) {
+ diag("branch out of range %d\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
}
- p->cond = q;
}
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- a = p->as;
- if(p->as == ATEXT)
- curtext = p;
- if(seenthumb && a == ABL) {
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(seenthumb && a == ABL) {
#ifdef CALLEEBX
- if(0)
- {}
+ if(0)
+ {}
#else
- if((s = p->to.sym) != S && (s->foreign || s->fnptr))
- p->as = ABX;
+ if((s = p->to.sym) != S && (s->foreign || s->fnptr))
+ p->as = ABX;
#endif
- else if(p->to.type == D_OREG)
- p->as = ABX;
- }
- if(p->cond != P && p->cond != UP) {
- p->cond = brloop(p->cond);
- if(p->cond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->cond->pc;
- }
- }
-}
-
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int32 dwn[LOG], cnt[LOG], i;
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
+ else if(p->to.type == D_OREG)
+ p->as = ABX;
+ }
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
}
}
}
@@ -543,462 +363,3 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
-
-#define Reachable(n) if((s = lookup(n, 0)) != nil) s->used++
-
-static void
-rused(Adr *a)
-{
- Sym *s = a->sym;
-
- if(s == S)
- return;
- if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
- if(a->name == D_EXTERN || a->name == D_STATIC){
- if(s->used == 0)
- s->used = 1;
- }
- }
- else if(a->type == D_BRANCH){
- if(s->used == 0)
- s->used = 1;
- }
-}
-
-void
-reachable()
-{
- Prog *p, *prev, *prevt, *nextt, *q;
- Sym *s, *s0;
- int i, todo;
- char *a;
-
- Reachable("_div");
- Reachable("_divu");
- Reachable("_mod");
- Reachable("_modu");
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return;
- s = lookup(a, 0);
- if(s == nil)
- return;
- if(s->type == 0){
- s->used = 1; // to stop asm complaining
- for(p = firstp; p != P && p->as != ATEXT; p = p->link)
- ;
- if(p == nil)
- return;
- s = p->from.sym;
- }
- s->used = 1;
- do{
- todo = 0;
- for(p = firstp; p != P; p = p->link){
- if(p->as == ATEXT && (s0 = p->from.sym)->used == 1){
- todo = 1;
- for(q = p->link; q != P && q->as != ATEXT; q = q->link){
- rused(&q->from);
- rused(&q->to);
- }
- s0->used = 2;
- }
- }
- for(p = datap; p != P; p = p->link){
- if((s0 = p->from.sym)->used == 1){
- todo = 1;
- for(q = p; q != P; q = q->link){ // data can be scattered
- if(q->from.sym == s0)
- rused(&q->to);
- }
- s0->used = 2;
- }
- }
- }while(todo);
- prev = nil;
- prevt = nextt = nil;
- for(p = firstp; p != P; ){
- if(p->as == ATEXT){
- prevt = nextt;
- nextt = p;
- }
- if(p->as == ATEXT && (s0 = p->from.sym)->used == 0){
- s0->type = SREMOVED;
- for(q = p->link; q != P && q->as != ATEXT; q = q->link)
- ;
- if(q != p->cond)
- diag("bad ptr in reachable()");
- if(prev == nil)
- firstp = q;
- else
- prev->link = q;
- if(q == nil)
- lastp = prev;
- if(prevt == nil)
- textp = q;
- else
- prevt->cond = q;
- if(q == nil)
- etextp = prevt;
- nextt = prevt;
- if(debug['V'])
- print("%s unused\n", s0->name);
- p = q;
- }
- else{
- prev = p;
- p = p->link;
- }
- }
- prevt = nil;
- for(p = datap; p != nil; ){
- if((s0 = p->from.sym)->used == 0){
- s0->type = SREMOVED;
- prev = prevt;
- for(q = p; q != nil; q = q->link){
- if(q->from.sym == s0){
- if(prev == nil)
- datap = q->link;
- else
- prev->link = q->link;
- }
- else
- prev = q;
- }
- if(debug['V'])
- print("%s unused (data)\n", s0->name);
- p = prevt->link;
- }
- else{
- prevt = p;
- p = p->link;
- }
- }
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->used == 0)
- s->type = SREMOVED;
- }
- }
-}
-
-static void
-fused(Adr *a, Prog *p, Prog *ct)
-{
- Sym *s = a->sym;
- Use *u;
-
- if(s == S)
- return;
- if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
- if(a->name == D_EXTERN || a->name == D_STATIC){
- u = malloc(sizeof(Use));
- u->p = p;
- u->ct = ct;
- u->link = s->use;
- s->use = u;
- }
- }
- else if(a->type == D_BRANCH){
- u = malloc(sizeof(Use));
- u->p = p;
- u->ct = ct;
- u->link = s->use;
- s->use = u;
- }
-}
-
-static int
-ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r)
-{
- int reg;
-
- USED(fp);
- USED(ct);
- if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
- reg = p->to.reg;
- for(p = p->link; p != P && p->as != ATEXT; p = p->link){
- if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg)
- return 1;
- if(!debug['F'] && (isbranch(p) || p->as == ARET)){
- // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name);
- return 0;
- }
- if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
- if(!debug['F'] && p->to.type != D_REG){
- // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name);
- return 0;
- }
- reg = p->to.reg;
- }
- }
- }
- // print("%s: no MOVW O(R), R\n", fp->name);
- return debug['F'];
-}
-
-static void
-setfpuse(Prog *p, Sym *fp, Sym *r)
-{
- int reg;
-
- if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
- reg = p->to.reg;
- for(p = p->link; p != P && p->as != ATEXT; p = p->link){
- if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){
- fp->fnptr = 0;
- p->as = ABL; // safe to do so
-// print("simplified %s call\n", fp->name);
- break;
- }
- if(!debug['F'] && (isbranch(p) || p->as == ARET))
- diag("bad setfpuse call");
- if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
- if(!debug['F'] && p->to.type != D_REG)
- diag("bad setfpuse call");
- reg = p->to.reg;
- }
- }
- }
-}
-
-static int
-cksymuse(Sym *s, int t)
-{
- Prog *p;
-
- for(p = datap; p != P; p = p->link){
- if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){
- // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t);
- return 0;
- }
- }
- return 1;
-}
-
-/* check the use of s at the given point */
-static int
-ckuse(Sym *s, Sym *s0, Use *u)
-{
- Sym *s1;
-
- s1 = u->p->from.sym;
-// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil");
- if(u->ct == nil){ /* in data area */
- if(s0 == s && !cksymuse(s1, s0->thumb)){
- // print("%s: cksymuse fails\n", s0->name);
- return 0;
- }
- for(u = s1->use; u != U; u = u->link)
- if(!ckuse(s1, s0, u))
- return 0;
- }
- else{ /* in text area */
- if(u->ct->from.sym->thumb != s0->thumb){
- // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb);
- return 0;
- }
- return ckfpuse(u->p, u->ct, s0, s);
- }
- return 1;
-}
-
-static void
-setuse(Sym *s, Sym *s0, Use *u)
-{
- Sym *s1;
-
- s1 = u->p->from.sym;
- if(u->ct == nil){ /* in data area */
- for(u = s1->use; u != U; u = u->link)
- setuse(s1, s0, u);
- }
- else{ /* in text area */
- setfpuse(u->p, s0, s);
- }
-}
-
-/* detect BX O(R) which can be done as BL O(R) */
-void
-fnptrs()
-{
- int i;
- Sym *s;
- Prog *p;
- Use *u;
-
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
- // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign);
- }
- }
- }
- /* record use of syms */
- for(p = firstp; p != P; p = p->link){
- if(p->as == ATEXT)
- curtext = p;
- else{
- fused(&p->from, p, curtext);
- fused(&p->to, p, curtext);
- }
- }
- for(p = datap; p != P; p = p->link)
- fused(&p->to, p, nil);
-
- /* now look for fn ptrs */
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
- for(u = s->use; u != U; u = u->link){
- if(!ckuse(s, s, u))
- break;
- }
- if(u == U){ // can simplify
- for(u = s->use; u != U; u = u->link)
- setuse(s, s, u);
- }
- }
- }
- }
-
- /* now free Use structures */
-}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- p->link = datap;
- datap = p;
- p->as = ADATA;
- p->reg = w;
- p->from.type = D_OREG;
- p->from.name = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->to.name = D_NONE;
- s->data = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = malloc(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.name = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- p->to.sval = malloc(NSNAME);
- memmove(p->to.sval, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.name = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- p->to.sval = malloc(NSNAME);
- memmove(p->to.sval, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
-}
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
new file mode 100644
index 000000000..ad115a8ca
--- /dev/null
+++ b/src/cmd/5l/prof.c
@@ -0,0 +1,214 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.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.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0 // TODO(rsc)
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = thumb ? REGTMPT : REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ setarch(p);
+ if(cursym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(cursym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * BL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BL profout
+ */
+ p->as = ABL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 82874ee1c..fd66b0969 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -5,67 +5,82 @@
#define EXTERN
#include "l.h"
+// Software floating point.
+
void
-softfloat()
+softfloat(void)
{
Prog *p, *next, *psfloat;
Sym *symsfloat;
int wasfloat;
-
+
+ if(!debug['F'])
+ return;
+
symsfloat = lookup("_sfloat", 0);
psfloat = P;
if(symsfloat->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symsfloat) {
- psfloat = p;
- break;
- }
- }
- }
+ psfloat = symsfloat->text;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ wasfloat = 0;
+ for(p = cursym->text; p != P; p = p->link)
+ if(p->cond != P)
+ p->cond->mark |= LABEL;
+ for(p = cursym->text; p != P; p = p->link) {
+ switch(p->as) {
+ case AMOVW:
+ if(p->to.type == D_FREG || p->from.type == D_FREG)
+ goto soft;
+ goto notsoft;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ case AMOVF:
+ case AMOVD:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ goto soft;
- wasfloat = 0;
- p = firstp;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- case AMOVF:
- case AMOVD:
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- if (psfloat == P)
- diag("floats used with _sfloat not defined");
- if (!wasfloat) {
- next = prg();
- *next = *p;
+ default:
+ goto notsoft;
- // BL _sfloat(SB)
- *p = zprg;
- p->link = next;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symsfloat;
- p->cond = psfloat;
+ soft:
+ if (psfloat == P)
+ diag("floats used with _sfloat not defined");
+ if (!wasfloat || (p->mark&LABEL)) {
+ next = prg();
+ *next = *p;
+
+ // BL _sfloat(SB)
+ *p = zprg;
+ p->link = next;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symsfloat;
+ p->cond = psfloat;
+
+ p = next;
+ wasfloat = 1;
+ }
+ break;
- p = next;
- wasfloat = 1;
+ notsoft:
+ wasfloat = 0;
}
- break;
- default:
- wasfloat = 0;
}
}
}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index a97af07f9..be0f5e8b3 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
@@ -52,9 +54,9 @@ ispad(Prog *p)
{
if(p->as != AMOVW)
return 0;
- if(p->from.type != D_REG || p->from.reg != REGSB)
+ if(p->from.type != D_REG || p->from.reg != REGTMP)
return 0;
- if(p->to.type != D_REG || p->to.reg != REGSB)
+ if(p->to.type != D_REG || p->to.reg != REGTMP)
return 0;
return 1;
}
@@ -100,7 +102,7 @@ fnpinc(Sym *s)
if(!debug['f'])
diag("fnptr == 0 in fnpinc");
if(s->foreign)
- diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);
+ diag("bad usage in fnpinc %s %d %d", s->name, s->foreign, s->thumb);
return 0;
}
/* 0, 1, 2, 3 squared */
@@ -119,9 +121,9 @@ pad(Prog *p, int pc)
q->as = AMOVW;
q->line = p->line;
q->from.type = D_REG;
- q->from.reg = REGSB;
+ q->from.reg = REGTMP;
q->to.type = D_REG;
- q->to.reg = REGSB;
+ q->to.reg = REGTMP;
q->pc = pc;
q->link = p->link;
return q;
@@ -132,7 +134,7 @@ scan(Prog *op, Prog *p, int c)
{
Prog *q;
- for(q = op->link; q != p; q = q->link){
+ for(q = op->link; q != p && q != P; q = q->link){
q->pc = c;
c += oplook(q)->size;
nocache(q);
@@ -163,11 +165,12 @@ void
span(void)
{
Prog *p, *op;
- Sym *setext, *s;
Optab *o;
- int m, bflag, i;
- int32 c, otxt, v;
+ int m, bflag, i, v;
+ int32 c, otxt, out[6];
int lastthumb = -1;
+ Section *sect;
+ uchar *bp;
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
@@ -176,61 +179,65 @@ span(void)
bflag = 0;
c = INITTEXT;
op = nil;
+ p = nil;
otxt = c;
- for(p = firstp; p != P; op = p, p = p->link) {
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
setarch(p);
p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool
- if(flushpool(op, 0, 1))
- c = p->pc = scan(op, p, c);
- }
- lastthumb = thumb;
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
- if(thumb && blitrl)
+ cursym->value = c;
+
+ lastthumb = thumb;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ if(thumb && blitrl)
+ pool.extra += brextra(p);
+
+ for(op = p, p = p->link; p != P; op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(blitrl){
+ if(thumb && isbranch(p))
pool.extra += brextra(p);
+ if(checkpool(op, p->as == ACASE ? casesz(p) : m))
+ c = p->pc = scan(op, p, c);
+ }
+ if(m == 0) {
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(p, &p->from);
+ break;
+ case LTO:
+ addpool(p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == 14)
+ flushpool(p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
flushpool(p, 0, 0);
- break;
+ c += m;
}
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- if(blitrl && p->link == P){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- checkpool(p, 0);
+ if(blitrl){
+ if(thumb && isbranch(op))
+ pool.extra += brextra(op);
+ if(checkpool(op, 0))
+ c = scan(op, P, c);
}
+ cursym->size = c - cursym->value;
}
/*
@@ -244,48 +251,52 @@ span(void)
Bprint(&bso, "%5.2f span1\n", cputime());
bflag = 0;
c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
-/* very larg branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+/* very large branches
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ bflag = 1;
+ }
}
- }
*/
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
}
@@ -304,107 +315,94 @@ span(void)
c = INITTEXT;
oop = op = nil;
again = 0;
- for(p = firstp; p != P; oop = op, op = p, p = p->link){
- setarch(p);
- if(p->pc != c)
- again = 1;
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
- m = o->size;
- if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
- if(p->as == ABL)
- m = 4;
- else
- m = 2;
- p->align = 0;
- }
- if(p->align){
- if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
- if(ispad(op)){
- oop->link = p;
- op = oop;
- c -= 2;
- p->pc = c;
- }
- else{
- op->link = pad(op, c);
- op = op->link;
- c += 2;
- p->pc = c;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; oop = op, op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ if(p->pc != c)
again = 1;
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+ m = o->size;
+ if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
+ if(p->as == ABL)
+ m = 4;
+ else
+ m = 2;
+ p->align = 0;
}
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
+ if(p->align){
+ if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
+ if(ispad(op)){
+ oop->link = p;
+ op = oop;
+ c -= 2;
+ p->pc = c;
+ }
+ else{
+ op->link = pad(op, c);
+ op = op->link;
+ c += 2;
+ p->pc = c;
+ }
+ again = 1;
+ }
+ }
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
}
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
if(c != lastc || again){
lastc = c;
goto loop;
}
}
-
- if(0 && seenthumb){ // rm redundant padding - obsolete
- int d;
-
- op = nil;
- d = 0;
- for(p = firstp; p != P; op = p, p = p->link){
- p->pc -= d;
- if(p->as == ATEXT){
- if(p->from.sym != S)
- p->from.sym->value -= d;
-// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
- }
- if(ispad(p) && p->link != P && ispad(p->link)){
- op->link = p->link->link;
- d += 4;
- p = op;
+ c = rnd(c, 8);
+
+ /*
+ * lay out the code. all the pc-relative code references,
+ * even cross-function, are resolved now;
+ * only data references need to be relocated.
+ * with more work we could leave cross-function
+ * code references to be relocated too, and then
+ * perhaps we'd be able to parallelize the span loop above.
+ */
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ setarch(p);
+ autosize = p->to.offset + 4;
+ symgrow(cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != P; p = p->link) {
+ curp = p;
+ pc = p->pc;
+ curp = p;
+ o = oplook(p);
+ asmout(p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ v = out[i];
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
}
}
- // print("%d bytes removed (padding)\n", d);
- c -= d;
}
-
- if(debug['t']) {
- /*
- * add strings to text segment
- */
- c = rnd(c, 8);
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SSTRING)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->value = c;
- c += v;
- }
- }
-
- c = rnd(c, 8);
-
- setext = lookup("etext", 0);
- if(setext != S) {
- setext->value = c;
- textsize = c - INITTEXT;
- }
- if(INITRND)
- INITDAT = rnd(c, INITRND);
- if(debug['v'])
- Bprint(&bso, "tsize = %lux\n", textsize);
- Bflush(&bso);
+ sect = addsection(&segtext, ".text", 05);
+ sect->vaddr = INITTEXT;
+ sect->len = c - INITTEXT;
}
/*
@@ -437,7 +435,7 @@ flushpool(Prog *p, int skip, int force)
if(blitrl) {
if(skip){
- if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
+ if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
q = prg();
q->as = AB;
q->to.type = D_BRANCH;
@@ -523,10 +521,10 @@ xdefine(char *p, int t, int32 v)
Sym *s;
s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
int32
@@ -583,6 +581,38 @@ immhalf(int32 v)
return 0;
}
+int32
+symaddr(Sym *s)
+{
+ int32 v;
+
+ v = s->value;
+ switch(s->type) {
+ default:
+ diag("unexpected type %d in symaddr(%s)", s->type, s->name);
+ return 0;
+
+ case STEXT:
+/* TODO(rsc): what is this for?
+#ifdef CALLEEBX
+ v += fnpinc(s);
+#else
+ if(s->thumb)
+ v++; // T bit
+#endif
+*/
+ break;
+
+ case SELFDATA:
+ case SRODATA:
+ case SDATA:
+ case SBSS:
+ case SCONST:
+ break;
+ }
+ return v;
+}
+
int
aclass(Adr *a)
{
@@ -619,36 +649,9 @@ aclass(Adr *a)
}
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(dlm) {
- switch(t) {
- default:
- instoffset = s->value + a->offset + INITDAT;
- break;
- case SUNDEF:
- case STEXT:
- case SCONST:
- case SLEAF:
- case SSTRING:
- instoffset = s->value + a->offset;
- break;
- }
- return C_ADDR;
- }
- instoffset = s->value + a->offset - BIG;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFEXT : C_HEXT;
- if(immfloat(t))
- return C_FEXT;
- return C_SEXT;
- }
- return C_LEXT;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
case D_AUTO:
instoffset = autosize + a->offset;
t = immaddr(instoffset);
@@ -703,32 +706,17 @@ aclass(Adr *a)
case D_STATIC:
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(s->type == SFIXED) {
- instoffset = s->value + a->offset;
- return C_LCON;
- }
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- return C_LCON;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
}
return C_GOK;
case D_FCONST:
- return C_FCON;
+ if(chipzero(&a->ieee) >= 0)
+ return C_ZFCON;
+ if(chipfloat(&a->ieee) >= 0)
+ return C_SFCON;
+ return C_LFCON;
case D_CONST:
case D_CONST2:
@@ -753,37 +741,7 @@ aclass(Adr *a)
if(s == S)
break;
t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case SFIXED:
- instoffset = s->value + a->offset;
- return C_LCON;
- case SUNDEF:
- case STEXT:
- case SSTRING:
- case SCONST:
- case SLEAF:
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- if(!dlm) {
- instoffset = s->value + a->offset - BIG;
- t = immrot(instoffset);
- if(t && instoffset != 0)
- return C_RECON;
- }
- instoffset = s->value + a->offset + INITDAT;
+ instoffset = 0; // s.b. unused but just in case
return C_LCON;
case D_AUTO:
@@ -895,21 +853,11 @@ cmp(int a, int b)
if(b == C_RACON)
return 1;
break;
- case C_LECON:
- if(b == C_RECON)
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
return 1;
break;
- case C_HFEXT:
- return b == C_HEXT || b == C_FEXT;
- case C_FEXT:
- case C_HEXT:
- return b == C_HFEXT;
- case C_SEXT:
- return cmp(C_HFEXT, b);
- case C_LEXT:
- return cmp(C_SEXT, b);
-
case C_HFAUTO:
return b == C_HAUTO || b == C_FAUTO;
case C_FAUTO:
@@ -1091,17 +1039,20 @@ buildop(void)
break;
case AMOVFW:
- oprange[AMOVWF] = oprange[r];
- oprange[AMOVWD] = oprange[r];
oprange[AMOVDW] = oprange[r];
break;
+ case AMOVWF:
+ oprange[AMOVWD] = oprange[r];
+ break;
+
case AMULL:
oprange[AMULA] = oprange[r];
oprange[AMULAL] = oprange[r];
oprange[AMULLU] = oprange[r];
oprange[AMULALU] = oprange[r];
break;
+
case ALDREX:
case ASTREX:
break;
@@ -1146,159 +1097,3 @@ buildrep(int x, int as)
oprange[as].start = 0;
}
*/
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = malloc(r->t*sizeof(uchar));
- r->a = na = malloc(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, int32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(v&3)
- diag("bad relocation address");
- v >>= 2;
- if(s != S && s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c
index 97292f640..b2ba630c3 100644
--- a/src/cmd/5l/thumb.c
+++ b/src/cmd/5l/thumb.c
@@ -203,9 +203,8 @@ thumbaclass(Adr *a, Prog *p)
a->sym->name, TNAME);
a->sym->type = SDATA;
}
- instoffset = a->sym->value + a->offset + INITDAT;
- return C_LEXT; /* INITDAT unknown at this stage */
- // return immacon(instoffset, p, C_SEXT, C_LEXT);
+ instoffset = a->sym->value + a->offset;
+ return C_ADDR; /* INITDAT unknown at this stage */
case D_AUTO:
instoffset = autosize + a->offset;
return immauto(instoffset, p);
@@ -235,8 +234,8 @@ thumbaclass(Adr *a, Prog *p)
s->name, TNAME);
s->type = SDATA;
}
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF){
+ instoffset = s->value + a->offset;
+ if(s->type == STEXT){
instoffset = s->value + a->offset;
#ifdef CALLEEBX
instoffset += fnpinc(s);
@@ -252,7 +251,7 @@ thumbaclass(Adr *a, Prog *p)
return C_GOK;
case D_FCONST:
diag("D_FCONST in thumaclass");
- return C_FCON;
+ return C_LFCON;
case D_CONST:
switch(a->name) {
case D_NONE:
@@ -275,7 +274,6 @@ thumbaclass(Adr *a, Prog *p)
break;
case SCONST:
case STEXT:
- case SLEAF:
instoffset = s->value + a->offset;
#ifdef CALLEEBX
instoffset += fnpinc(s);
@@ -285,7 +283,7 @@ thumbaclass(Adr *a, Prog *p)
#endif
return C_LCON;
}
- instoffset = s->value + a->offset + INITDAT;
+ instoffset = s->value + a->offset;
return C_LCON; /* INITDAT unknown at this stage */
// return immcon(instoffset, p);
case D_AUTO:
@@ -358,8 +356,8 @@ thumbaclass(Adr *a, Prog *p)
// as a1 a2 a3 type size param lit vers
Optab thumboptab[] =
{
- { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
{ AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 },
{ ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 },
{ ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 },
@@ -412,37 +410,27 @@ Optab thumboptab[] =
{ ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 17, 4, 0 },
{ ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 },
{ AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP },
{ AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM },
// { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM },
- { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 },
{ AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
{ AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
{ AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
{ AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 },
{ AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 },
@@ -469,16 +457,16 @@ Optab thumboptab[] =
{ AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
{ AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },
};
@@ -683,7 +671,7 @@ thumbasmout(Prog *p, Optab *o)
rt = p->to.reg;
r = p->reg;
o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0;
-if(debug['P']) print("%ulx: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
+if(debug['P']) print("%ux: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
opcount[o->type] += o->size;
switch(o->type) {
default:
@@ -691,7 +679,7 @@ if(debug['P']) print("%ulx: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->al
prasm(p);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
+if(debug['G']) print("%ux: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 1: /* op R, -, R or op R, R, - */
o1 = thumboprr(p->as);
@@ -981,6 +969,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
}
break;
case 30: /* AMOVW... *addr, R */
+ diag("likely broken"); // does this still refer to SB?
thumbaclass(&p->from, p);
o1 = mv(p, rt, instoffset); // MOV addr, rtmp
o2 = thumbopmv(p->as, 1);
@@ -988,6 +977,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R
break;
case 31: /* AMOVW... R, *addr */
+ diag("likely broken"); // does this still refer to SB?
thumbaclass(&p->to, p);
o1 = mv(p, REGTMPT, instoffset);
o2 = thumbopmv(p->as, 0);
@@ -1162,29 +1152,29 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
switch(o->size) {
default:
if(debug['a'])
- Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
break;
case 2:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
hputl(o1);
break;
case 4:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux\t%P\n", v, o1, o2, p);
hputl(o1);
hputl(o2);
break;
case 6:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, p);
hputl(o1);
hputl(o2);
hputl(o3);
break;
case 8:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1192,7 +1182,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 10:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1201,7 +1191,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 12:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1211,7 +1201,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 14:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1223,12 +1213,12 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
}
if(debug['G']){
if(o->type == 17){
- print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
+ print("%x: word %d\n", p->pc, (o2<<16)+o1);
return;
}
if(o->type == 50){
- print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
- print("%lx: word %ld\n", p->pc, (o4<<16)+o3);
+ print("%x: word %d\n", p->pc, (o2<<16)+o1);
+ print("%x: word %d\n", p->pc, (o4<<16)+o3);
return;
}
if(o->size > 0) dis(o1, p->pc);
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
index 21d824708..30180bd24 100644
--- a/src/cmd/6a/Makefile
+++ b/src/cmd/6a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6a\
+TARG=6a
HFILES=\
a.h\
@@ -20,21 +20,6 @@ OFILES=\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index a713acc9f..9030081ca 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/6a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -50,7 +50,7 @@ typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -161,6 +161,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -168,9 +169,9 @@ EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
-void* alloc(int32);
+void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index 804f638a0..770f676fe 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/6a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -60,7 +60,11 @@
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
@@ -453,6 +457,12 @@ omem:
$$.type = D_INDIR+D_SP;
$$.offset = $1;
}
+| con '(' LSREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 81273b297..1b8bb6344 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/6a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -1260,10 +1260,10 @@ jackpot:
}
Bputc(&obuf, a);
Bputc(&obuf, a>>8);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(&g2->from, sf);
zaddr(&g2->to, st);
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
index 53a8e80e6..484e16def 100644
--- a/src/cmd/6c/Makefile
+++ b/src/cmd/6c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6c\
+TARG=6c
HFILES=\
gc.h\
@@ -28,18 +28,9 @@ OFILES=\
../6l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
index 39452c989..90394884f 100644
--- a/src/cmd/6c/cgen.c
+++ b/src/cmd/6c/cgen.c
@@ -57,6 +57,12 @@ cgen(Node *n, Node *nn)
l = n->left;
r = n->right;
o = n->op;
+
+ if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
+ gmove(n, nn);
+ return;
+ }
+
if(n->addable >= INDEXED) {
if(nn == Z) {
switch(o) {
@@ -1922,7 +1928,7 @@ vaddr(Node *n, int a)
int32
hi64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)(n->vconst) & ~0L;
else
return (int32)((uvlong)n->vconst>>32) & ~0L;
@@ -1931,7 +1937,7 @@ hi64v(Node *n)
int32
lo64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)((uvlong)n->vconst>>32) & ~0L;
else
return (int32)(n->vconst) & ~0L;
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
index d67ef8df7..bad6c5e27 100644
--- a/src/cmd/6c/div.c
+++ b/src/cmd/6c/div.c
@@ -120,7 +120,7 @@ sdivgen(Node *l, Node *r, Node *ax, Node *dx)
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
-//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+//print("a=%d i=%d s=%d m=%ux\n", a, (long)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
@@ -141,7 +141,7 @@ udivgen(Node *l, Node *r, Node *ax, Node *dx)
Node nod;
a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (long)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
index ba517ca0a..4293203c0 100644
--- a/src/cmd/6c/list.c
+++ b/src/cmd/6c/list.c
@@ -78,22 +78,23 @@ Pconv(Fmt *fp)
p = va_arg(fp->args, Prog*);
switch(p->as) {
case ADATA:
- sprint(str, " %A %D/%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
+ sprint(str, "(%L) %A %D/%d,%D",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
case ATEXT:
if(p->from.scale) {
- sprint(str, " %A %D,%d,%lD",
- p->as, &p->from, p->from.scale, &p->to);
+ sprint(str, "(%L) %A %D,%d,%lD",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
- sprint(str, " %A %D,%lD",
- p->as, &p->from, &p->to);
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
break;
default:
- sprint(str, " %A %D,%lD", p->as, &p->from, &p->to);
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
break;
}
return fmtstrcpy(fp, str);
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
index eefeacaed..ab6883e7a 100644
--- a/src/cmd/6c/mul.c
+++ b/src/cmd/6c/mul.c
@@ -355,7 +355,7 @@ mulgen1(uint32 v, Node *n)
mulparam(v, p);
found:
-// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
index 01793bfc5..13fd25e73 100644
--- a/src/cmd/6c/peep.c
+++ b/src/cmd/6c/peep.c
@@ -797,8 +797,6 @@ copyu(Prog *p, Adr *v, Adr *s)
return 3;
case ACALL: /* funny */
- if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
- return 2;
if(REGARG >= 0 && v->type == REGARG)
return 2;
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
index 431501202..996128f75 100644
--- a/src/cmd/6c/reg.c
+++ b/src/cmd/6c/reg.c
@@ -448,7 +448,7 @@ regopt(Prog *p)
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] |
@@ -1113,7 +1113,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -1123,21 +1123,21 @@ paint1(Reg *r, int bn)
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1174,7 +1174,7 @@ regset(Reg *r, uint32 bb)
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
- diag(Z, "zero v.type for %#lux", b);
+ diag(Z, "zero v.type for %#ux", b);
c = copyu(r->prog, &v, A);
if(c == 3)
set |= b;
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
index b8247a1b7..42045f8fa 100644
--- a/src/cmd/6c/sgen.c
+++ b/src/cmd/6c/sgen.c
@@ -131,6 +131,10 @@ xcom(Node *n)
n->addable = 11;
break;
+ case OEXREG:
+ n->addable = 0;
+ break;
+
case OREGISTER:
n->addable = 12;
break;
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 668a1fdbc..47975a0c8 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -503,7 +503,7 @@ zaddr(Biobuf *b, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -517,7 +517,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_VLONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -525,10 +527,13 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_VLONG)
- w = SZ_VLONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else
+ w = ewidth[v->etype];
+ if(w < 1 || w > SZ_VLONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -538,8 +543,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesu[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -560,13 +565,15 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1);
- o = align(o, t, Ael2);
+ o = align(o, t, Ael1, nil);
+ o = align(o, t, Ael2, nil);
break;
}
o = xround(o, w);
+ if(maxalign && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index f96c40f8e..a78ba227b 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -38,8 +38,7 @@ ginit(void)
thechar = '6';
thestring = "amd64";
- exregoffset = REGEXT;
- exfregoffset = FREGEXT;
+ dodefine("_64BIT");
listinit();
nstring = 0;
mnstring = 0;
@@ -425,7 +424,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -441,22 +440,22 @@ regaalloc1(Node *n, Node *nn)
diag(n, "regaalloc1 and REGARG<0");
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -491,6 +490,10 @@ naddr(Node *n, Adr *a)
a->sym = S;
break;
+ case OEXREG:
+ a->type = D_INDIR + D_GS;
+ a->offset = n->reg - 1;
+ break;
case OIND:
naddr(n->left, a);
@@ -1502,11 +1505,11 @@ exreg(Type *t)
int32 o;
if(typechlpv[t->etype]) {
- if(exregoffset <= REGEXT-4)
+ if(exregoffset >= 64)
return 0;
o = exregoffset;
- exregoffset--;
- return o;
+ exregoffset += 8;
+ return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
}
return 0;
}
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
index 712cfc60c..023f5d111 100644
--- a/src/cmd/6g/Makefile
+++ b/src/cmd/6g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6g
+TARG=6g
HFILES=\
../gc/go.h\
@@ -26,18 +26,9 @@ OFILES=\
../6l/enam.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f $(TARG) enam.c 6.out a.out *.$O *.6
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../gc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index aacc0d06f..d4d22fd61 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -418,7 +418,7 @@ void
agen(Node *n, Node *res)
{
Node *nl, *nr;
- Node n1, n2, n3, tmp, n4;
+ Node n1, n2, n3, tmp, n4, n5;
Prog *p1;
uint32 w;
uint64 v;
@@ -477,8 +477,10 @@ agen(Node *n, Node *res)
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
goto index;
}
tempname(&tmp, nr->type);
@@ -486,8 +488,10 @@ agen(Node *n, Node *res)
nr = &tmp;
irad:
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
if(!isconst(nr, CTINT)) {
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
@@ -501,7 +505,7 @@ agen(Node *n, Node *res)
// explicit check for nil if array is large enough
// that we might derive too big a pointer.
- if(!isslice(nl->type) && nl->type->width >= unmappedzero) {
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
regalloc(&n4, types[tptr], &n3);
gmove(&n3, &n4);
n4.op = OINDREG;
@@ -516,15 +520,16 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index"); // front end should handle
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT64], v);
+ nodconst(&n2, types[TUINT32], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(panicindex, 0);
@@ -536,18 +541,9 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
-
+ ginscon(optoas(OADD, types[tptr]), v*w, &n3);
gmove(&n3, res);
regfree(&n3);
break;
@@ -564,20 +560,43 @@ agen(Node *n, Node *res)
if(!debug['B'] && !n->etype) {
// check bounds
- if(isslice(nl->type)) {
+ n5.op = OXXX;
+ t = types[TUINT32];
+ if(is64(nr->type))
+ t = types[TUINT64];
+ if(isconst(nl, CTSTR)) {
+ nodconst(&n1, t, nl->val.u.sval->len);
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
- n1.type = types[tptr];
+ n1.type = types[TUINT32];
n1.xoffset = Array_nel;
- } else
- nodconst(&n1, types[TUINT64], nl->type->bound);
- gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(is64(nr->type)) {
+ regalloc(&n5, t, N);
+ gmove(&n1, &n5);
+ n1 = n5;
+ }
+ } else {
+ nodconst(&n1, t, nl->type->bound);
+ }
+ gins(optoas(OCMP, t), &n2, &n1);
+ p1 = gbranch(optoas(OLT, t), T);
+ if(n5.op != OXXX)
+ regfree(&n5);
ginscall(panicindex, 0);
patch(p1, pc);
}
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ p1 = gins(ALEAQ, N, &n3);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ p1->from.scale = 1;
+ p1->from.index = n2.val.u.reg;
+ goto indexdone;
+ }
+
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -591,12 +610,12 @@ agen(Node *n, Node *res)
p1->from.index = p1->from.type;
p1->from.type = p1->to.type + D_INDIR;
} else {
- nodconst(&n1, t, w);
- gins(optoas(OMUL, t), &n1, &n2);
+ ginscon(optoas(OMUL, t), w, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
gmove(&n3, res);
}
+ indexdone:
gmove(&n3, res);
regfree(&n2);
regfree(&n3);
@@ -616,10 +635,8 @@ agen(Node *n, Node *res)
fatal("agen: bad ONAME class %#x", n->class);
}
cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
break;
case OIND:
@@ -628,10 +645,8 @@ agen(Node *n, Node *res)
case ODOT:
agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
break;
case ODOTPTR:
@@ -648,8 +663,7 @@ agen(Node *n, Node *res)
gins(ATESTB, nodintconst(0), &n1);
regfree(&n1);
}
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
}
break;
}
@@ -694,6 +708,9 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
@@ -1006,6 +1023,10 @@ sgen(Node *n, Node *ns, int32 w)
if(w < 0)
fatal("sgen copy %d", w);
+ if(w == 16)
+ if(componentgen(n, ns))
+ return;
+
// offset on the stack
osrc = stkof(n);
odst = stkof(ns);
@@ -1099,3 +1120,163 @@ sgen(Node *n, Node *ns, int32 w)
restx(&nodr, &oldr);
restx(&cx, &oldcx);
}
+
+static int
+cadable(Node *n)
+{
+ if(!n->addable) {
+ // dont know how it happens,
+ // but it does
+ return 0;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * copy a structure component by component
+ * return 1 if can do, 0 if cant.
+ * nr is N for copy zero
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+ Node nodl, nodr;
+ int freel, freer;
+
+ freel = 0;
+ freer = 0;
+
+ switch(nl->type->etype) {
+ default:
+ goto no;
+
+ case TARRAY:
+ if(!isslice(nl->type))
+ goto no;
+ case TSTRING:
+ case TINTER:
+ break;
+ }
+
+ nodl = *nl;
+ if(!cadable(nl)) {
+ if(nr == N || !cadable(nr))
+ goto no;
+ igen(nl, &nodl, N);
+ freel = 1;
+ }
+
+ if(nr != N) {
+ nodr = *nr;
+ if(!cadable(nr)) {
+ igen(nr, &nodr, N);
+ freer = 1;
+ }
+ }
+
+ switch(nl->type->etype) {
+ case TARRAY:
+ if(!isslice(nl->type))
+ goto no;
+
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(nl->type->type);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_cap-Array_nel;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_cap-Array_nel;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRING:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TINTER:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRUCT:
+ goto no;
+ }
+
+no:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 0;
+
+yes:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 1;
+}
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 68647e21b..bdfc9947e 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 8;
widthptr = 8;
zprog.link = P;
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 353a86dcd..7efb2c252 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -99,6 +99,7 @@ void cgen_aret(Node*, Node*);
int cgen_inline(Node*, Node*);
void restx(Node*, Node*);
void savex(int, Node*, Node*, Node*, Type*);
+int componentgen(Node*, Node*);
/*
* gsubr.c
@@ -122,6 +123,7 @@ Node* nodarg(Type*, int);
void nodreg(Node*, Type*, int);
void nodindreg(Node*, Type*, int);
void gconreg(int, vlong, int);
+void ginscon(int, vlong, Node*);
void buildtxt(void);
Plist* newplist(void);
int isfat(Type*);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 59a6d529d..d9fa1793c 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -62,6 +62,8 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+ setlineno(curfn);
+
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
@@ -83,6 +85,8 @@ compile(Node *fn)
checklabels();
if(nerrors != 0)
goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
@@ -90,13 +94,13 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer)
- ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
@@ -105,11 +109,11 @@ compile(Node *fn)
}
// fill in argument size
- ptxt->to.offset = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
ptxt->to.offset <<= 32;
- ptxt->to.offset |= rnd(stksize+maxarg, maxround);
+ ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
if(debug['f'])
frame(0);
@@ -1041,7 +1045,12 @@ clearfat(Node *nl)
if(debug['g'])
dump("\nclearfat", nl);
+
w = nl->type->width;
+ if(w == 16)
+ if(componentgen(N, nl))
+ return;
+
c = w % 8; // bytes
q = w / 8; // quads
@@ -1115,44 +1124,64 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
Node *c;
+ Type *t;
+ Node n1;
+
+ if(nl->op == OCONV && is64(nl->type))
+ nl = nl->left;
+ if(nr->op == OCONV && is64(nr->type))
+ nr = nr->left;
op = OLE;
if(smallintconst(nl)) {
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AJMP, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
-
// put the constant on the right
op = brrev(op);
c = nl;
nl = nr;
nr = c;
}
-
- gins(optoas(OCMP, types[TUINT32]), nl, nr);
+ if(is64(nr->type) && smallintconst(nr))
+ nr->type = types[TUINT32];
+
+ n1.op = OXXX;
+ t = types[TUINT32];
+ if(nl->type->width != t->width || nr->type->width != t->width) {
+ if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL))
+ t = types[TUINT64];
+
+ // Check if we need to use a temporary.
+ // At least one of the arguments is 32 bits
+ // (the len or cap) so one temporary suffices.
+ if(nl->type->width != t->width && nl->op != OLITERAL) {
+ regalloc(&n1, t, nl);
+ gmove(nl, &n1);
+ nl = &n1;
+ } else if(nr->type->width != t->width && nr->op != OLITERAL) {
+ regalloc(&n1, t, nr);
+ gmove(nr, &n1);
+ nr = &n1;
+ }
+ }
+ gins(optoas(OCMP, t), nl, nr);
+ if(n1.op != OXXX)
+ regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
throwpc = pc;
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
patch(p1, throwpc);
}
}
@@ -1183,6 +1212,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -1261,10 +1292,8 @@ slicearray:
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) *
mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
+ if(v != 0)
+ ginscon(optoas(OADD, types[tptr]), v, &nodes[0]);
} else {
regalloc(&n1, types[tptr], &nodes[2]);
gmove(&nodes[2], &n1);
@@ -1310,6 +1339,7 @@ sliceslice:
// if(lb[1] > old.nel[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
@@ -1329,6 +1359,7 @@ sliceslice:
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2);
// if(lb[1] > hb[2]) goto throw;
@@ -1376,10 +1407,8 @@ sliceslice:
gins(optoas(OAS, types[tptr]), &n2, &n1);
v = mpgetfix(nodes[1].val.u.xval) *
mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n2, &n1);
- }
+ if(v != 0)
+ ginscon(optoas(OADD, types[tptr]), v, &n1);
} else {
gmove(&nodes[1], &n1);
if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index 7c05054b7..b667ae48a 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -633,7 +633,7 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
}
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Sym *e;
int c, d, o, mov, add, loaded;
@@ -732,7 +732,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 52ff6fdea..ebb61ea94 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -147,6 +147,8 @@ ggloblnod(Node *nam, int32 width)
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
}
void
@@ -163,6 +165,7 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.offset = width;
if(dupok)
p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
}
int
@@ -427,11 +430,33 @@ fatal("shouldnt be used");
void
gconreg(int as, vlong c, int reg)
{
- Node n1, n2;
+ Node nr;
+
+ nodreg(&nr, types[TINT64], reg);
+ ginscon(as, c, &nr);
+}
+
+/*
+ * generate
+ * as $c, n
+ */
+void
+ginscon(int as, vlong c, Node *n2)
+{
+ Node n1, ntmp;
nodconst(&n1, types[TINT64], c);
- nodreg(&n2, types[TINT64], reg);
- gins(as, &n1, &n2);
+
+ if(as != AMOVQ && (c < -1LL<<31 || c >= 1LL<<31)) {
+ // cannot have 64-bit immediokate in ADD, etc.
+ // instead, MOV into register first.
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVQ, &n1, &ntmp);
+ gins(as, &ntmp, n2);
+ regfree(&ntmp);
+ return;
+ }
+ gins(as, &n1, n2);
}
#define CASE(a,b) (((a)<<16)|((b)<<0))
@@ -1683,12 +1708,28 @@ optoas(int op, Type *t)
enum
{
- ODynam = 1<<0,
+ ODynam = 1<<0,
+ OAddable = 1<<1,
};
static Node clean[20];
static int cleani = 0;
+int
+xgen(Node *n, Node *a, int o)
+{
+ regalloc(a, types[tptr], N);
+
+ if(o & ODynam)
+ if(n->addable)
+ if(n->op != OINDREG)
+ if(n->op != OREGISTER)
+ return 1;
+
+ agen(n, a);
+ return 0;
+}
+
void
sudoclean(void)
{
@@ -1716,7 +1757,7 @@ sudoaddable(int as, Node *n, Addr *a)
int o, i, w;
int oary[10];
int64 v;
- Node n1, n2, n3, *nn, *l, *r;
+ Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
Prog *p1;
Type *t;
@@ -1743,6 +1784,8 @@ sudoaddable(int as, Node *n, Addr *a)
goto odot;
case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
goto oindex;
}
return 0;
@@ -1820,7 +1863,7 @@ oindex:
if(l->type->etype != TARRAY)
fatal("not ary");
if(l->type->bound < 0)
- o += ODynam;
+ o |= ODynam;
w = n->type->width;
if(isconst(r, CTINT))
@@ -1836,9 +1879,6 @@ oindex:
break;
}
-// if(sudoaddable(as, l, a))
-// goto oindex_sudo;
-
cleani += 2;
reg = &clean[cleani-1];
reg1 = &clean[cleani-2];
@@ -1847,8 +1887,8 @@ oindex:
// load the array (reg)
if(l->ullman > r->ullman) {
- regalloc(reg, types[tptr], N);
- agen(l, reg);
+ if(xgen(l, reg, o))
+ o |= OAddable;
}
// load the index (reg1)
@@ -1863,49 +1903,89 @@ oindex:
// load the array (reg)
if(l->ullman <= r->ullman) {
- regalloc(reg, types[tptr], N);
- agen(l, reg);
+ if(xgen(l, reg, o))
+ o |= OAddable;
}
if(!(o & ODynam) && l->type->width >= unmappedzero && l->op == OIND) {
// cannot rely on page protections to
// catch array ptr == 0, so dereference.
n2 = *reg;
+ n2.xoffset = 0;
n2.op = OINDREG;
n2.type = types[TUINT8];
- n2.xoffset = 0;
gins(ATESTB, nodintconst(0), &n2);
}
// check bounds
if(!debug['B'] && !n->etype) {
+ // check bounds
+ n4.op = OXXX;
+ t = types[TUINT32];
if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_nel;
+ if(o & OAddable) {
+ n2 = *l;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ if(is64(r->type)) {
+ t = types[TUINT64];
+ regalloc(&n4, t, N);
+ gmove(&n2, &n4);
+ n2 = n4;
+ }
+ } else {
+ n2 = *reg;
+ n2.xoffset = Array_nel;
+ n2.op = OINDREG;
+ n2.type = types[TUINT32];
+ if(is64(r->type)) {
+ t = types[TUINT64];
+ regalloc(&n4, t, N);
+ gmove(&n2, &n4);
+ n2 = n4;
+ }
+ }
} else {
+ if(is64(r->type))
+ t = types[TUINT64];
nodconst(&n2, types[TUINT64], l->type->bound);
}
- gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ gins(optoas(OCMP, t), reg1, &n2);
+ p1 = gbranch(optoas(OLT, t), T);
+ if(n4.op != OXXX)
+ regfree(&n4);
ginscall(panicindex, 0);
patch(p1, pc);
}
if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_array;
- gmove(&n2, reg);
+ if(o & OAddable) {
+ n2 = *l;
+ n2.xoffset += Array_array;
+ n2.type = types[TUINT64];
+ gmove(&n2, reg);
+ } else {
+ n2 = *reg;
+ n2.xoffset = Array_array;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ gmove(&n2, reg);
+ }
}
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->type;
- a->type = reg->val.u.reg + D_INDIR;
+ if(o & OAddable) {
+ naddr(reg1, a, 1);
+ a->offset = 0;
+ a->scale = w;
+ a->index = a->type;
+ a->type = reg->val.u.reg + D_INDIR;
+ } else {
+ naddr(reg1, a, 1);
+ a->offset = 0;
+ a->scale = w;
+ a->index = a->type;
+ a->type = reg->val.u.reg + D_INDIR;
+ }
goto yes;
@@ -1915,15 +1995,6 @@ oindex_const:
// can multiply by width statically
v = mpgetfix(r->val.u.xval);
- if(!debug['B'] && (o & ODynam) == 0) {
- // array indexed by a constant bounds check
- if(v < 0) {
- yyerror("out of bounds on array");
- } else
- if(v >= l->type->bound) {
- yyerror("out of bounds on array");
- }
- }
if(sudoaddable(as, l, a))
goto oindex_const_sudo;
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
index 9194b1dab..c8077c97a 100644
--- a/src/cmd/6g/list.c
+++ b/src/cmd/6g/list.c
@@ -47,24 +47,28 @@ Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
+ char scale[40];
p = va_arg(fp->args, Prog*);
sconsize = 8;
+ scale[0] = '\0';
+ if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
+ snprint(scale, sizeof scale, "%d,", p->from.scale);
switch(p->as) {
default:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%D",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
case ADATA:
sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%lD",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
}
return fmtstrcpy(fp, str);
@@ -104,7 +108,7 @@ Dconv(Fmt *fp)
if(a->branch == nil)
snprint(str, sizeof(str), "<nil>");
else
- snprint(str, sizeof(str), "%ld", a->branch->loc);
+ snprint(str, sizeof(str), "%d", a->branch->loc);
break;
case D_EXTERN:
@@ -127,7 +131,7 @@ Dconv(Fmt *fp)
if(fp->flags & FmtLong) {
d1 = a->offset & 0xffffffffLL;
d2 = (a->offset>>32) & 0xffffffffLL;
- snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
+ snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
break;
}
snprint(str, sizeof(str), "$%lld", a->offset);
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index e92740e04..464627066 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -682,17 +682,17 @@ brk:
print("\nstats\n");
if(ostats.ncvtreg)
- print(" %4ld cvtreg\n", ostats.ncvtreg);
+ print(" %4d cvtreg\n", ostats.ncvtreg);
if(ostats.nspill)
- print(" %4ld spill\n", ostats.nspill);
+ print(" %4d spill\n", ostats.nspill);
if(ostats.nreload)
- print(" %4ld reload\n", ostats.nreload);
+ print(" %4d reload\n", ostats.nreload);
if(ostats.ndelmov)
- print(" %4ld delmov\n", ostats.ndelmov);
+ print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4ld delmov\n", ostats.nvar);
+ print(" %4d delmov\n", ostats.nvar);
if(ostats.naddr)
- print(" %4ld delmov\n", ostats.naddr);
+ print(" %4d delmov\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -1268,7 +1268,7 @@ regset(Reg *r, uint32 bb)
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
- fatal("zero v.type for %#lux", b);
+ fatal("zero v.type for %#ux", b);
c = copyu(r->prog, &v, A);
if(c == 3)
set |= b;
@@ -1486,7 +1486,7 @@ dumpone(Reg *r)
int z;
Bits bit;
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] =
r->set.b[z] |
@@ -1535,14 +1535,14 @@ dumpit(char *str, Reg *r0)
if(r1 != R) {
print(" pred:");
for(; r1 != R; r1 = r1->p2link)
- print(" %.4lud", r1->prog->loc);
+ print(" %.4ud", r1->prog->loc);
print("\n");
}
// r1 = r->s1;
// if(r1 != R) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4lud", r1->prog->loc);
+// print(" %.4ud", r1->prog->loc);
// print("\n");
// }
}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index ca5e485c0..709f82ccc 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
/*
* amd64
@@ -389,8 +390,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -823,6 +824,7 @@ enum
D_INDIR, /* additive */
D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
+ D_PCREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index 72bde4465..fba1b42ae 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -2,23 +2,29 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6l\
+TARG=6l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
obj.$O\
optab.$O\
pass.$O\
+ prof.$O\
span.$O\
+ symtab.$O\
HFILES=\
l.h\
@@ -26,20 +32,14 @@ HFILES=\
../ld/lib.h\
../ld/elf.h\
../ld/macho.h\
+ ../ld/dwarf.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 6.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+CLEANFILES+=enam.c
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index b45557ebe..9726d227c 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -28,9 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../ld/macho.h"
#define Dbufslop 100
@@ -41,7 +44,6 @@ char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
char freebsddynld[] = "/libexec/ld-elf.so.1";
char zeroes[32];
-Prog* datsort(Prog *l);
vlong
entryvalue(void)
@@ -55,15 +57,8 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
@@ -113,130 +108,13 @@ vputl(uint64 v)
lputl(v>>32);
}
-void
-strnput(char *s, int n)
-{
- int i;
-
- for(i=0; i<n; i++) {
- cput(*s);
- if(*s != 0)
- s++;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > sizeof(p->to.scon))
- m = sizeof(p->to.scon);
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- memmove(p->to.scon, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 8 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 8 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT)
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
diag("datoff %#llx", addr);
return 0;
}
@@ -260,6 +138,8 @@ enum {
ElfStrShstrtab,
ElfStrSymtab,
ElfStrStrtab,
+ ElfStrRelaPlt,
+ ElfStrPlt,
NElfStr
};
@@ -281,29 +161,461 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rela, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_X86_64_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_X86_64_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ 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);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_X86_64_64:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ // Handle relocations found in Mach-O object files.
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
+ // TODO: What is the difference between all these?
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+ r->type = D_PCREL;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+ 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);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
+ if(targ->dynimpname == nil || targ->dynexport)
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, s, r->off);
+ if(r->siz == 8)
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+ else
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+ adduint64(rela, r->add);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation
+ // that is too much bother to deal with.
+ // Instead, interpret the C declaration
+ // void *_Cvar_stderr = &stderr;
+ // as making _Cvar_stderr the name of a GOT entry
+ // for stderr. This is separate from the usual GOT entry,
+ // just in case the C code assigns to the variable,
+ // and of course it only works for single pointers,
+ // but we only need to support cgo and that's all it needs.
+ adddynsym(targ);
+ got = lookup(".got", 0);
+ s->type = got->type | SSUB;
+ s->outer = got;
+ s->sub = got->sub;
+ got->sub = s;
+ s->value = got->size;
+ adduint64(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ return -1;
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushq got+8(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addpcrelplus(plt, got, 8);
+
+ // jmpq got+16(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, 16);
+
+ // nopl 0(AX)
+ adduint32(plt, 0x00401f0f);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint64(got, 0);
+ adduint64(got, 0);
+ }
+}
+
+static void
+addpltsym(Sym *s)
+{
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ Sym *plt, *got, *rela;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rela = lookup(".rela.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushq $x
+ adduint8(plt, 0x68);
+ adduint32(plt, (got->size-24-8)/8);
+
+ // jmpq .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rela
+ addaddrplus(rela, got, got->size-8);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+ adduint64(rela, 0);
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // To do lazy symbol lookup right, we're supposed
+ // to tell the dynamic loader which library each
+ // symbol comes from and format the link info
+ // section just so. I'm too lazy (ha!) to do that
+ // so for now we'll just use non-lazy pointers,
+ // which don't need to be told which library to use.
+ //
+ // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+ // has details about what we're avoiding.
+
+ Sym *plt;
+
+ addgotsym(s);
+ plt = lookup(".plt", 0);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rela;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint64(got, 0);
+
+ if(iself) {
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, got, s->got);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+ adduint64(rela, 0);
+ } else if(HEADTYPE == 6) { // Mach-O
+ adduint32(lookup(".linkedit.got", 0), s->dynid);
+ } else {
+ diag("addgotsym: unsupported binary format");
+ }
+}
+
+void
+adddynsym(Sym *s)
+{
+ Sym *d, *str;
+ int t;
+ char *name;
+
+ if(s->dynid >= 0)
+ return;
+
+ if(s->dynimpname == nil)
+ diag("adddynsym: no dynamic name for %s", s->name);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+
+ /* reserved */
+ adduint8(d, 0);
+
+ /* section where symbol is defined */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size of object */
+ adduint64(d, 0);
+
+ if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
+ addstring(lookup(".dynstr", 0), s->dynimplib));
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-o symbol nlist64
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/16;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ if(s->type == SDYNIMPORT) {
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ } else {
+ adduint8(d, 0x0f);
+ switch(s->type) {
+ default:
+ case STEXT:
+ adduint8(d, 1);
+ break;
+ case SDATA:
+ adduint8(d, 2);
+ break;
+ case SBSS:
+ adduint8(d, 4);
+ break;
+ }
+ }
+ adduint16(d, 0); // desc
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0); // value
+ else
+ addaddr(d, s);
+ } else {
+ diag("adddynsym: unsupported binary format");
+ }
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == 6) { // Mach-O
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(HEADTYPE != 7 && HEADTYPE != 9)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
+ shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".elfdata");
+ addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
- if(debug['e']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- }
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -316,19 +628,21 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
+ elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* dynamic symbol table - first entry all zeros */
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
+ s->size += ELF64SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -339,15 +653,24 @@ doelf(void)
/* global offset table */
s = lookup(".got", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* got.plt - ??? */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* hash */
- s = lookup(".hash", 0);
+ elfsetupplt();
+
+ s = lookup(".rela.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
@@ -355,78 +678,10 @@ doelf(void)
s = lookup(".dynamic", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
-
- /*
- * relocation entries for dynimport symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rela", 0);
- addaddr(d, s);
- adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64));
- adduint64(d, 0);
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- /* value */
- if(!s->dynexport)
- adduint64(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint64(d, 0);
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
-
- elfdynhash(nsym);
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
@@ -437,6 +692,11 @@ doelf(void)
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_RELA);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -463,15 +723,13 @@ phsh(ElfPhdr *ph, ElfShdr *sh)
void
asmb(void)
{
- Prog *p;
- int32 v, magic;
+ int32 magic;
int a, dynsym;
- uchar *op1;
vlong vl, va, startva, fo, w, symo, elfsymo, elfstro, elfsymsize, machlink;
- vlong symdatva = SYMDATVA;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -481,101 +739,51 @@ asmb(void)
elfsymsize = 0;
elfstro = 0;
elfsymo = 0;
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->pc != pc) {
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- curp = p;
- asmins(p);
- a = (andptr - and);
- if(cbc < a)
- cflush();
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1);
- for(; op1 < and+Maxand; op1++)
- Bprint(&bso, " ");
- Bprint(&bso, "%P\n", curp);
- }
- if(dlm) {
- if(p->as == ATEXT)
- reloca = nil;
- else if(reloca != nil)
- diag("reloc failure: %P", curp);
- }
- memmove(cbp, and, a);
- cbp += a;
- pc += a;
- cbc -= a;
- }
- cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f codeblk\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
+
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ machlink = 0;
+ if(HEADTYPE == 6)
+ machlink = domacholink();
switch(HEADTYPE) {
default:
- diag("unknown header type %ld", HEADTYPE);
+ diag("unknown header type %d", HEADTYPE);
case 2:
case 5:
- seek(cout, HEADR+textsize, 0);
break;
case 6:
debug['8'] = 1; /* 64-bit addresses */
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
break;
-
case 7:
case 9:
debug['8'] = 1; /* 64-bit addresses */
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
-
/* index of elf text section; needed by asmelfsym, double-checked below */
- /* debug['d'] causes 8 extra sections before the .text section */
+ /* !debug['d'] causes extra sections before the .text section */
elftextsh = 1;
if(!debug['d'])
- elftextsh += 8;
+ elftextsh += 10;
break;
}
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- datap = datsort(datap);
- for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
- if(datsize-v > sizeof(buf)-Dbufslop)
- datblk(v, sizeof(buf)-Dbufslop);
- else
- datblk(v, datsize-v);
- }
-
- machlink = 0;
- if(HEADTYPE == 6)
- machlink = domacholink();
-
symsize = 0;
spsize = 0;
lcsize = 0;
@@ -589,14 +797,14 @@ asmb(void)
case 2:
case 5:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.len+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
case 7:
case 9:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
@@ -608,8 +816,6 @@ asmb(void)
* line number table
*/
seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f sp\n", cputime());
Bflush(&bso);
@@ -617,30 +823,26 @@ asmb(void)
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(!debug['s'])
strnput("", INITRND-(8+symsize+lcsize)%INITRND);
cflush();
seek(cout, symo, 0);
lputl(symsize);
lputl(lcsize);
cflush();
- if(!debug['s'] && debug['e']) {
+ if(!debug['s']) {
elfsymo = symo+8+symsize+lcsize;
seek(cout, elfsymo, 0);
- asmelfsym();
+ asmelfsym64();
cflush();
elfstro = seek(cout, 0, 1);
elfsymsize = elfstro - elfsymo;
- write(cout, elfstrdat, elfstrsize);
- }
- } else
- if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
+ ewrite(cout, elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfemitdebugsections();
+ }
}
if(debug['v'])
@@ -652,12 +854,10 @@ asmb(void)
case 2: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
- if(dlm)
- magic |= 0x80000000; /* dlm */
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
vl = entryvalue();
lputb(PADDR(vl)); /* va of entry */
@@ -667,19 +867,17 @@ asmb(void)
break;
case 3: /* plan9 */
magic = 4*26*26+7;
- if(dlm)
- magic |= 0x80000000;
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
lputb(entryvalue()); /* va of entry */
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
case 7:
case 9:
@@ -689,7 +887,7 @@ asmb(void)
fo = HEADR;
startva = INITTEXT - HEADR;
va = startva + fo;
- w = textsize;
+ w = segtext.filelen;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
@@ -724,41 +922,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- ph->vaddr = va - fo;
- ph->paddr = va - fo;
- ph->off = 0;
- ph->filesz = w + fo;
- ph->memsz = w + fo;
- ph->align = INITRND;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s']) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -776,7 +941,7 @@ asmb(void)
sh->entsize = 8;
sh->addralign = 8;
shsym(sh, lookup(".got.plt", 0));
-
+
dynsym = eh->shnum;
sh = newElfShdr(elfstr[ElfStrDynsym]);
sh->type = SHT_DYNSYM;
@@ -793,6 +958,22 @@ asmb(void)
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+ sh = newElfShdr(elfstr[ElfStrRelaPlt]);
+ sh->type = SHT_RELA;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF64RELASIZE;
+ sh->addralign = 8;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rela.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 16;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
+
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
sh->flags = SHF_ALLOC;
@@ -821,6 +1002,17 @@ asmb(void)
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
phsh(ph, sh);
+
+ /*
+ * Thread-local storage segment (really just size).
+ */
+ if(tlsoffset != 0) {
+ ph = newElfPhdr();
+ ph->type = PT_TLS;
+ ph->flags = PF_R;
+ ph->memsz = -tlsoffset;
+ ph->align = 8;
+ }
}
ph = newElfPhdr();
@@ -828,93 +1020,41 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 8;
- fo = ELFRESERVE;
- va = startva + fo;
- w = textsize;
-
if(elftextsh != eh->shnum)
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 8;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = 8;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 8;
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
- sh = newElfShdr(elfstr[ElfStrGosymcounts]);
+ sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
+ shsym(sh, lookup("symtab", 0));
- sh = newElfShdr(elfstr[ElfStrGosymtab]);
+ sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
+ shsym(sh, lookup("pclntab", 0));
- fo += w;
- w = lcsize;
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = elfsymo;
+ sh->size = elfsymsize;
+ sh->addralign = 8;
+ sh->entsize = 24;
+ sh->link = eh->shnum; // link to strtab
- sh = newElfShdr(elfstr[ElfStrGopclntab]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = elfstro;
+ sh->size = elfstrsize;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
-
- if(debug['e']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
- sh->addralign = 8;
- sh->entsize = 24;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = elfstro;
- sh->size = elfstrsize;
- sh->addralign = 1;
- }
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -961,354 +1101,91 @@ cflush(void)
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
-void
-outa(int n, uchar *cast, uchar *map, vlong l)
-{
- int i, j;
-
- Bprint(&bso, pcstr, l);
- for(i=0; i<n; i++) {
- j = i;
- if(map != nil)
- j = map[j];
- Bprint(&bso, "%.2ux", cast[j]);
- }
- for(; i<Maxand; i++)
- Bprint(&bso, " ");
- Bprint(&bso, "%P\n", curp);
-}
-
-/*
- * divide-and-conquer list-link
- * sort of Prog* structures.
- * Used for the data block.
- */
-int
-datcmp(Prog *p1, Prog *p2)
+/* Current position in file */
+vlong
+cpos(void)
{
- vlong v1, v2;
-
- v1 = p1->from.offset;
- v2 = p2->from.offset;
- if(v1 > v2)
- return +1;
- if(v1 < v2)
- return -1;
- return 0;
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
-Prog*
-dsort(Prog *l)
-{
- Prog *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = dsort(l);
- l2 = dsort(l2);
-
- /* set up lead element */
- if(datcmp(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if(datcmp(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-static Prog *datp;
-
-Prog*
-datsort(Prog *l)
+vlong
+rnd(vlong v, vlong r)
{
- Prog *p;
- Adr *a;
+ vlong c;
- for(p = l; p != P; p = p->link) {
- a = &p->from;
- a->offset += a->sym->value;
- }
- datp = dsort(l);
- return datp;
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
}
void
-datblk(int32 s, int32 n)
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
- Prog *p;
- uchar *cast;
- int32 l, fl, j;
- vlong o;
- int i, c;
- Adr *a;
-
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
- l = a->offset - s;
- if(l+a->scale < 0)
- continue;
- datp = p;
- break;
- }
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
-
- l = a->offset - s;
- if(l >= n)
- break;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
+ Auto *a;
+ Sym *s;
+ int h;
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ case SMACHOGOT:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
continue;
- i = -l;
- l = 0;
- }
-
- curp = p;
- if(!a->sym->reachable)
- diag("unreachable symbol in datblk - %s", a->sym->name);
- if(a->sym->type == SMACHO)
- continue;
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization for %d %d", s, j);
- break;
- }
- }
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.scon[i];
- l++;
- }
- break;
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, o);
- if(p->to.sym->type == Sxxx) {
- curtext = p; // show useful name in diag's output
- diag("missing symbol %s", p->to.sym->name);
- }
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- fl = o;
- cast = (uchar*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (uchar*)&o;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi8[i]];
- l++;
- }
- break;
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
}
- break;
}
}
- write(cout, buf.dbuf, n);
- if(!debug['a'])
- return;
-
- /*
- * a second pass just to print the asm
- */
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0)
- continue;
-
- if(a->sym->type == SMACHO)
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
continue;
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- outa(c, cast, fnuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- outa(c, cast, fnuxi8, l+s+INITDAT);
- break;
- }
- break;
-
- case D_SCONST:
- outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
- break;
-
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.sym) {
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- }
- }
- fl = o;
- cast = (uchar*)&fl;
- switch(c) {
- case 1:
- outa(c, cast, inuxi1, l+s+INITDAT);
- break;
- case 2:
- outa(c, cast, inuxi2, l+s+INITDAT);
- break;
- case 4:
- outa(c, cast, inuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&o;
- outa(c, cast, inuxi8, l+s+INITDAT);
- break;
- }
- break;
- }
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
}
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
}
-
-vlong
-rnd(vlong v, vlong r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index a74e9b5c0..501317f36 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -32,8 +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)
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_amd64.
-r dir1:dir2:...
Set the dynamic linker search path when using ELF.
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 3db0b450a..1c52ea89d 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -44,7 +44,7 @@ enum
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define TNAME (curtext?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
@@ -56,6 +56,7 @@ typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Movtab Movtab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -67,11 +68,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
char index;
char scale;
@@ -83,18 +80,25 @@ struct Adr
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int64 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
vlong pc;
+ int32 spadj;
int32 line;
short as;
char ft; /* oclass cache */
@@ -102,9 +106,12 @@ struct Prog
uchar mark; /* work on these */
uchar back;
- char width; /* fake for DATA */
+ char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +122,39 @@ struct Auto
};
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar special;
+ int32 dynid;
+ int32 sig;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
vlong value;
vlong size;
- int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
struct Optab
{
@@ -154,21 +175,25 @@ struct Movtab
enum
{
Sxxx,
+
+ /* order here is order in output file */
STEXT = 1,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHOGOT,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
-
- SMACHO,
- SFIXED,
- SELFDATA,
+ SDYNIMPORT,
+ SSUB = 1<<8,
NHASH = 10007,
NHUNK = 100000,
@@ -274,8 +299,6 @@ enum
Rxx = 1<<1, /* extend sib index */
Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
Maxand = 10, /* in -a output width of the byte codes */
};
@@ -300,35 +323,30 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN vlong INITDAT;
EXTERN int32 INITRND;
EXTERN vlong INITTEXT;
+EXTERN vlong INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int cbc;
EXTERN char* cbp;
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN vlong datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN vlong elfdatsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
-EXTERN Prog* firstp;
-EXTERN int xrefresolv;
+EXTERN Sym* textp;
+EXTERN Sym* etextp;
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar* rexptr;
EXTERN uchar and[30];
EXTERN int reg[D_NONE];
EXTERN int regrex[D_NONE+1];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int nerrors;
EXTERN char* noname;
@@ -338,8 +356,7 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
-EXTERN vlong textsize;
+EXTERN int tlsoffset;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
@@ -347,45 +364,29 @@ EXTERN char* paramspace;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-EXTERN Adr* reloca;
-EXTERN int doexp; // export table
-EXTERN int dlm; // dynamically loadable module
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
EXTERN vlong textstksiz;
EXTERN vlong textarg;
extern char thechar;
-EXTERN int dynptrsize;
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
EXTERN int elftextsh;
-#define UP (&undefp)
-
extern Optab optab[];
extern Optab* opindex[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(int32, int);
void addstackmark(void);
Prog* appendp(Prog*);
-vlong addstring(Sym*, char*);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong addaddr(Sym*, Sym*);
-vlong addsize(Sym*, Sym*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
void asmelfsym(void);
vlong atolwhex(char*);
@@ -393,35 +394,29 @@ Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
void datblk(int32, int32);
void deadcode(void);
void diag(char*, ...);
-void dobss(void);
void dodata(void);
void doelf(void);
-void doinit(void);
void domacho(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
vlong entryvalue(void);
-void export(void);
void follow(void);
void gethunk(void);
void gotypestrings(void);
-void import(void);
void listinit(void);
Sym* lookup(char*, int);
void lputb(int32);
void lputl(int32);
+void instinit(void);
void main(int, char*[]);
-void mkfwd(void);
void* mysbrk(uint32);
-Prog* newdata(Sym*, int, int, int);
Prog* newtext(Prog*, Sym*);
void nopout(Prog*);
int opsize(Prog*);
@@ -429,19 +424,14 @@ void patch(void);
Prog* prg(void);
void parsetextconst(vlong);
int relinv(int);
-int32 reuse(Prog*, Sym*);
vlong rnd(vlong, vlong);
void span(void);
-void strnput(char*, int);
void undef(void);
-vlong vaddr(Adr*);
vlong symaddr(Sym*);
void vputl(uint64);
void wputb(uint16);
void wputl(uint16);
void xdefine(char*, int, vlong);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
void machsymseg(uint32, uint32);
@@ -460,3 +450,9 @@ uint32 machheadr(void);
#pragma varargck type "R" int
#pragma varargck type "A" int
#pragma varargck argpos diag 1
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 7
+};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index 195e11d1d..f39efa2e8 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -42,46 +44,36 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
- if(p == P)
- return fmtstrcpy(fp, "<P>");
-
bigP = p;
-
- snprint(str1, sizeof(str1), "(%ld)", p->line);
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- snprint(str, sizeof(str), "%-7s %-7A %D,%d,%lD",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ fmtprint(fp, "(%d) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
- snprint(str, sizeof(str), "%-7s %-7A %D,%lD",
- str1, p->as, &p->from, &p->to);
- break;
-
default:
- snprint(str, sizeof(str), "%-7s %-7A %D,%D",
- str1, p->as, &p->from, &p->to);
+ fmtprint(fp, "(%d) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
break;
-
case ADATA:
- case AINIT:
- case ADYNT:
- snprint(str, sizeof(str), "%-7s %-7A %D/%d,%D",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A %D/%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -187,7 +179,7 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
@@ -402,19 +394,48 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uchar *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uchar*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n; i++)
+ fmtprint(&fmt, "%.2ux", *p++);
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
if(nerrors > 20) {
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 5a4b6a3fc..96d78c3b9 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -28,11 +28,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/dwarf.h"
#include <ar.h>
char *noname = "<none>";
@@ -51,28 +54,6 @@ char* paramspace = "FP";
* options used: 189BLQSWabcjlnpsvz
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else {
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
void
usage(void)
{
@@ -83,7 +64,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -187,6 +168,11 @@ main(int argc, char *argv[])
INITRND = 4096;
break;
case 6: /* apple MACH */
+ /*
+ * OS X system constant - offset from 0(GS) to our TLS.
+ * Explained in ../../libcgo/darwin_amd64.c.
+ */
+ tlsoffset = 0x8a0;
machoinit();
HEADR = MACHORESERVE;
if(INITRND == -1)
@@ -198,6 +184,13 @@ main(int argc, char *argv[])
break;
case 7: /* elf64 executable */
case 9: /* freebsd */
+ /*
+ * ELF uses TLS offset negative from FS.
+ * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+ * Also known to ../../pkg/runtime/linux/amd64/sys.s
+ * and ../../libcgo/linux_amd64.s.
+ */
+ tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -209,117 +202,13 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%llux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- ycover[Ym*Ymax + Ymm] = 1;
- ycover[Ymr*Ymax + Ymm] = 1;
-
- ycover[Yax*Ymax + Yxm] = 1;
- ycover[Ycx*Ymax + Yxm] = 1;
- ycover[Yrx*Ymax + Yxm] = 1;
- ycover[Yrl*Ymax + Yxm] = 1;
- ycover[Ym*Ymax + Yxm] = 1;
- ycover[Yxr*Ymax + Yxm] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
@@ -334,50 +223,20 @@ main(int argc, char *argv[])
pcstr = "%.6llux ";
nuxiinit();
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
-
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- errorexit();
-
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- import();
- HEADTYPE = 2;
- INITTEXT = 0;
- INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
-
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
- dobss();
dostkoff();
paramspace = "SP"; /* (FP) now (SP) on output */
if(debug['p'])
@@ -386,12 +245,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%d symbols\n", nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
@@ -400,8 +265,19 @@ main(int argc, char *argv[])
errorexit();
}
-void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = Bgetc(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
@@ -425,7 +301,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
a->sym = S;
if(t & T_SYM)
- a->sym = h[Bgetc(f)];
+ a->sym = zsym(pn, f, h);
a->type = D_NONE;
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
@@ -438,16 +314,17 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
if(t & T_TYPE)
a->type = Bgetc(f);
+ if(a->type < 0 || a->type >= D_SIZE)
+ mangle(pn);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
s = a->sym;
- if(s == S)
- return;
-
t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += tlsoffset;
if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
+ if(s && adrgotype)
s->gotype = adrgotype;
return;
}
@@ -484,7 +361,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
vlong ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip, mode;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -492,7 +369,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int ntext;
vlong eof;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -549,7 +428,7 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures"
- "%lux(%s) and %lux(%s) for %s",
+ "%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
@@ -557,6 +436,8 @@ loop:
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -571,6 +452,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -582,9 +464,18 @@ loop:
p->mode = mode;
p->ft = 0;
p->tt = 0;
- zaddr(f, &p->from, h);
+ zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->to, h);
+
+ switch(p->as) {
+ case ATEXT:
+ case ADATA:
+ case AGLOBL:
+ if(p->from.sym == S)
+ mangle(pn);
+ break;
+ }
if(debug['W'])
print("%P\n", p);
@@ -606,10 +497,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -618,89 +509,41 @@ loop:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
goto loop;
- case ADYNT:
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->from.scale = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(p->from.sym == S)
- break;
-
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- goto data;
-
- case AINIT:
- if(p->from.sym == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- goto data;
-
case ADATA:
- data:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->link = P;
+ savedata(s, p);
+ unmal(p, sizeof *p);
goto loop;
case AGOK:
@@ -710,23 +553,29 @@ loop:
case ATEXT:
s = p->from.sym;
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
+ }
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(debug['v'])
Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
- }
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ s->text = p;
+ cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
@@ -739,7 +588,10 @@ loop:
diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AMODE:
@@ -772,24 +624,12 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -817,25 +657,14 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
+ sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -847,13 +676,18 @@ loop:
default:
if(skip)
nopout(p);
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ goto loop;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
goto loop;
}
goto loop;
@@ -895,154 +729,3 @@ appendp(Prog *q)
p->mode = q->mode;
return p;
}
-
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
-
- if(p->from.scale & NOPROF) { /* dont profile */
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
-
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
index c729f0e23..6cc50313e 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -783,7 +783,7 @@ Optab optab[] =
{ AMOVBWSX, ymb_rl, Pq, 0xbe },
{ AMOVBWZX, ymb_rl, Pq, 0xb6 },
{ AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf2, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
{ AMOVHLPS, yxr, Pm, 0x12 },
{ AMOVHPD, yxmov, Pe, 0x16,0x17 },
{ AMOVHPS, yxmov, Pm, 0x16,0x17 },
@@ -907,9 +907,9 @@ Optab optab[] =
{ APOPQ, ypopl, Py, 0x58,0x8f,(00) },
{ APOPW, ypopl, Pe, 0x58,0x8f,(00) },
{ APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pw, Pe,0xf6 },
+ { APSADBW, yxm, Pq, 0xf6 },
{ APSHUFHW, yxshuf, Pf3, 0x70 },
- { APSHUFL, yxm, Pw, Pe,0x70 },
+ { APSHUFL, yxshuf, Pq, 0x70 },
{ APSHUFLW, yxshuf, Pf2, 0x70 },
{ APSHUFW, ymshuf, Pm, 0x70 },
{ APSLLO, ypsdq, Pq, 0x73,(07) },
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index f86942926..5c4ed00a6 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -28,9 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
+static void xfol(Prog*, Prog**);
+
// see ../../runtime/proc.c:/StackGuard
enum
{
@@ -38,157 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- curtext = p; // for diag messages
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%lld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->value = t;
- if(t > MINSIZ)
- continue;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- if(datsize)
- datsize = rnd(datsize, 8);
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-}
-
-void
-dobss(void)
-{
- int i;
- Sym *s;
- int32 t;
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 8);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- if(t >= 8)
- bsssize = rnd(bsssize, 8);
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -205,19 +58,61 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -226,55 +121,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
-
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -287,8 +158,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -296,14 +167,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -312,15 +182,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
- a == ARETFL || a == ARETFQ || a == ARETFW)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -328,7 +205,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -376,32 +253,11 @@ relinv(int a)
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
+ errorexit();
return a;
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -419,58 +275,58 @@ patch(void)
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 7 || HEADTYPE == 9) {
+ // ELF uses FS instead of GS.
+ if(p->from.type == D_INDIR+D_GS)
+ p->from.type = D_INDIR+D_FS;
+ if(p->to.type == D_INDIR+D_GS)
+ p->to.type = D_INDIR+D_FS;
+ }
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
+ if((s->type&~SSUB) != STEXT) {
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
}
+ if(s->text == nil)
+ continue;
p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
}
}
- if(p->to.type != D_BRANCH || p->pcond == UP)
+ if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
- continue;
- }
+ for(q = cursym->text; q != P;) {
if(c == q->pc)
break;
- q = q->link;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
if(q == P) {
- diag("branch out of range in %s\n%P [%s]",
- TNAME, p, p->to.sym ? p->to.sym->name : "<nil>");
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
+ if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
@@ -479,40 +335,6 @@ patch(void)
}
}
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
-}
-
Prog*
brloop(Prog *p)
{
@@ -553,378 +375,275 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome, pcsize;
+ int a, pcsize;
uint32 moreconst1, moreconst2, i;
for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0);
- pmorestack[i] = P;
- }
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- for(i=0; i<nelem(morename); i++) {
- if(p->from.sym == symmorestack[i]) {
- pmorestack[i] = p;
- break;
- }
- }
- }
- }
-
- for(i=0; i<nelem(morename); i++) {
- if(pmorestack[i] == P)
- diag("morestack trampoline not defined");
- }
-
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
-
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
- }
- break;
- }
+ if(symmorestack[i]->type != STEXT)
+ diag("morestack trampoline not defined - %s", morename[i]);
+ pmorestack[i] = symmorestack[i]->text;
}
autoffset = 0;
deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- if(!(p->from.scale & NOSPLIT)) {
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack?
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_R15;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_R15;
- }
+ p = cursym->text;
+ parsetextconst(p->to.offset);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
+ diag("nosplit func likely to overflow stack");
+
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ p->as = AMOVQ;
+ if(HEADTYPE == 7 || HEADTYPE == 9) // ELF uses FS
+ p->from.type = D_INDIR+D_FS;
+ else
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset+0;
+ p->to.type = D_CX;
+
+ if(debug['K']) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 8;
+ p->to.type = D_SP;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- moreconst1 = 0;
- if(autoffset+160 > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
- moreconst2 = textarg;
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack?
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
} else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
+ // large stack
+ p = appendp(p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- }
-
- if(q != P)
- q->pcond = p->link;
- if(autoffset) {
+ // common
p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
}
- deltasp = autoffset;
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 0;
- p->to.type = D_BX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ moreconst1 = 0;
+ if(autoffset+160+textarg > 4096)
+ moreconst1 = (autoffset+160) & ~7LL;
+ moreconst2 = textarg;
- p = appendp(p);
- p->as = ASUBQ;
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[0];
+ p->to.sym = symmorestack[0];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AJHI;
+ p->as = ACALL;
p->to.type = D_BRANCH;
- q1 = p;
+ p->pcond = pmorestack[1];
+ p->to.sym = symmorestack[1];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[i];
+ p->to.sym = symmorestack[i];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AINT;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[2];
+ p->to.sym = symmorestack[2];
+ } else {
+ p->as = AMOVQ;
p->from.type = D_CONST;
- p->from.offset = 3;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[3];
+ p->to.sym = symmorestack[3];
}
}
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
+ p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
- p->from.offset = -autoffset;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+ if(debug['K'] > 1 && autoffset) {
+ // 6l -KK means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
p = appendp(p);
- p->as = ARET;
- }
- continue;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
+ p = appendp(p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+
+ for(; p != P; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(p);
+ p->as = ARET;
+ }
+ }
}
}
@@ -975,180 +694,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
new file mode 100644
index 000000000..25992a40b
--- /dev/null
+++ b/src/cmd/6l/prof.c
@@ -0,0 +1,171 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.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.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 15f931bcb..5251f19bb 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -28,34 +28,33 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
-#include "../ld/elf.h"
static int rexflag;
static int asmode;
+static vlong vaddr(Adr*, Reloc*);
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v;
- vlong c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ if(s->p != nil)
+ return;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -70,378 +69,253 @@ span(void)
p->as = ANOP;
}
}
+
n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
-start:
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- asmins(p);
- p->pc = c;
- m = andptr-and;
- p->mark = m;
- c += m;
- }
-
-loop:
- n++;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping\n");
- errorexit();
- }
- again = 0;
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH || p->back & 0100) {
- if(p->back)
- p->pc = c;
asmins(p);
+ p->pc = c;
m = andptr-and;
- if(m != p->mark) {
- p->mark = m;
- again++;
- }
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
}
- p->pc = c;
- c += p->mark;
- }
- if(again) {
- textsize = c;
- goto loop;
- }
- if(INITRND) {
- INITDAT = rnd(c, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(++n > 20) {
+ diag("span must be looping");
+ errorexit();
+ }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %llux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, vlong v)
+span(void)
{
- Sym *s;
+ Prog *p, *q;
+ int32 v;
+ int n;
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
-void
-putsymb(char *s, int t, vlong v, vlong size, int ver, Sym *go)
-{
- int i, f, l;
- vlong gv;
-
- if(t == 'f')
- s++;
- l = 4;
- if(!debug['8']){
- lputb(v>>32);
- l = 8;
- }
- lputb(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- diag("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- if(l == 8)
- lputb(gv>>32);
- lputb(gv);
- symsize += l + 1 + i+1 + l;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->p != nil)
+ continue;
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8llux %s %s (%.8llux)\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-genasmsym(void (*put)(char*, int, vlong, vlong, int, Sym*))
+xdefine(char *p, int t, vlong v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s->name, 'B', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SFIXED:
- put(s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(p = textp; p != P; p = p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- put(a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- if(!s->reachable)
- continue;
- put(s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(".frame", 'm', p->to.offset+8, 0, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmsym(void)
+instinit(void)
{
- genasmsym(putsymb);
-}
+ int c, i;
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-
-int
-putelfstr(char *s)
-{
- int off, n;
-
- if(elfstrsize == 0 && s[0] != 0) {
- // first entry must be empty string
- putelfstr("");
- }
-
- n = strlen(s)+1;
- if(elfstrsize+n > maxelfstr) {
- maxelfstr = 2*(elfstrsize+n+(1<<20));
- elfstrdat = realloc(elfstrdat, maxelfstr);
- }
- off = elfstrsize;
- elfstrsize += n;
- memmove(elfstrdat+off, s, n);
- return off;
-}
-
-void
-putelfsymb(char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
- break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
- break;
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil) {
+ diag("phase error in optab: %d (%A)", i, c);
+ errorexit();
+ }
+ opindex[c] = &optab[i];
}
-
- stroff = putelfstr(s);
- lputl(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- wputl(shndx);
- vputl(addr);
- vputl(size);
-}
-void
-asmelfsym(void)
-{
- genasmsym(putelfsymb);
-}
-
-void
-asmlc(void)
-{
- vlong oldpc;
- Prog *p;
- int32 oldlc, v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['O'])
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- continue;
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ ycover[Ym*Ymax + Ymm] = 1;
+ ycover[Ymr*Ymax + Ymm] = 1;
+
+ ycover[Yax*Ymax + Yxm] = 1;
+ ycover[Ycx*Ymax + Yxm] = 1;
+ ycover[Yrx*Ymax + Yxm] = 1;
+ ycover[Yrl*Ymax + Yxm] = 1;
+ ycover[Ym*Ymax + Yxm] = 1;
+ ycover[Yxr*Ymax + Yxm] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(debug['O'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['O'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['O']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['O']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['O']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
}
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+}
+
+int
+prefixof(Adr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
}
- if(debug['v'] || debug['O'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
+ return 0;
}
int
@@ -641,11 +515,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -670,10 +544,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[(int)a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -719,7 +593,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d/%d/%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -727,10 +601,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -739,12 +609,25 @@ put4(int32 v)
}
static void
-put8(vlong v)
+relput4(Prog *p, Adr *a)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */
- reloca = nil;
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
}
+ put4(v);
+}
+
+static void
+put8(vlong v)
+{
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -756,24 +639,41 @@ put8(vlong v)
andptr += 8;
}
+/*
+static void
+relput8(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + andptr - and;
+ }
+ put8(v);
+}
+*/
+
vlong
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-vlong
-vaddr(Adr *a)
+static vlong
+vaddr(Adr *a, Reloc *r)
{
int t;
vlong v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -783,34 +683,18 @@ vaddr(Adr *a)
case D_STATIC:
case D_EXTERN:
s = a->sym;
- if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if((uvlong)s->value < (uvlong)INITTEXT)
- v += INITTEXT; /* TO DO */
- v += s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- default:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
- }
+ if(!s->reachable)
+ diag("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
return v;
}
@@ -819,55 +703,51 @@ static void
asmandsz(Adr *a, int r, int rex, int m64)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
rex &= (0x40 | Rxr);
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR) {
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+ rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
return;
}
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmandsz(&aa, r, rex, m64);
- return;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
}
if(t >= D_AL && t <= D_X0+15) {
if(v)
@@ -876,72 +756,84 @@ asmandsz(Adr *a, int r, int rex, int m64)
rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
return;
}
- if(t >= D_INDIR) {
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
t -= D_INDIR;
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- if(asmode != 64){
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
- return;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- put4(v);
+
+ rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ if(asmode != 64){
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmandsz(&aa, r, rex, m64);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -1173,14 +1065,25 @@ doasm(Prog *p)
Prog *q, pp;
uchar *t;
Movtab *mo;
- int z, op, ft, tt, xo, l;
+ int z, op, ft, tt, xo, l, pre;
vlong v;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
o = opindex[p->as];
if(o == nil) {
diag("asmins: missing op %P", p);
return;
}
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *andptr++ = pre;
if(p->ft == 0)
p->ft = oclass(&p->from);
@@ -1244,7 +1147,7 @@ found:
diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
if(op == 0x0f) {
*andptr++ = op;
@@ -1350,64 +1253,74 @@ found:
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmando(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zibo_m_xm:
z = mediaop(o, op, t[3], z);
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
*andptr++ = op;
- *andptr++ = v;
+ *andptr++ = vaddr(a, nil);
break;
case Zib_rp:
rexflag |= regrex[p->to.type] & (Rxb|0x40);
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zo_iw:
*andptr++ = op;
if(p->from.type != D_NONE){
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
break;
case Ziq_rp:
+ v = vaddr(&p->from, &rel);
l = v>>32;
- if(l == 0){
+ if(l == 0 && rel.siz != 8){
//p->mark |= 0100;
//print("zero: %llux %P\n", v, p);
rexflag &= ~(0x40|Rxw);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put4(v);
}else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
//p->mark |= 0100;
@@ -1419,6 +1332,11 @@ found:
//print("all: %llux %P\n", v, p);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put8(v);
}
break;
@@ -1426,53 +1344,54 @@ found:
case Zib_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmando(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmando(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1490,74 +1409,132 @@ found:
asmand(&p->to, &p->to);
break;
- case Zbr:
+ case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
+ *andptr++ = op;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
break;
- case Zcall:
+ case Zbr:
+ case Zjmp:
+ // TODO: jump across functions needs reloc
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
}
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
}
- break;
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
- case Zjmp:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+*/
+ break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ if(q == nil) {
+ diag("loop without target");
+ errorexit();
}
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
break;
case Zbyte:
+ v = vaddr(&p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1730,6 +1707,7 @@ void
asmins(Prog *p)
{
int n, np, c;
+ Reloc *r;
rexflag = 0;
andptr = and;
@@ -1739,7 +1717,7 @@ asmins(Prog *p)
/*
* as befits the whole approach of the architecture,
* the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3 prefix bytes, but
+ * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
* before the 0f opcode escape!), or it might be ignored.
* note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
*/
@@ -1748,164 +1726,16 @@ asmins(Prog *p)
n = andptr - and;
for(np = 0; np < n; np++) {
c = and[np];
- if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
break;
}
+ for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ r->off++;
+ }
memmove(and+np+1, and+np, n-np);
and[np] = 0x40 | rexflag;
andptr++;
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lputb(0);
- t = 0;
- lputb(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lputb(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lputb(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wputb(ra);
- t += 2;
- }
- else{
- lputb(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lputb(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
index beb575544..78d361dbd 100644
--- a/src/cmd/8a/Makefile
+++ b/src/cmd/8a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8a\
+TARG=8a
HFILES=\
a.h\
@@ -20,21 +20,6 @@ OFILES=\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index 035db2551..fe6b17280 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/8a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -50,7 +50,7 @@ typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -162,6 +162,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -169,9 +170,9 @@ EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
-void* alloc(int32);
+void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 8bc96cce5..04662f83d 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/8a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -64,7 +64,11 @@
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index c8127bde9..bf298b266 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/8a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// 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)
@@ -925,10 +925,10 @@ jackpot:
}
Bputc(&obuf, a);
Bputc(&obuf, a>>8);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(&g2->from, sf);
zaddr(&g2->to, st);
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
index 85ea3013b..60f46d3c9 100644
--- a/src/cmd/8c/Makefile
+++ b/src/cmd/8c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8c\
+TARG=8c
HFILES=\
gc.h\
@@ -29,18 +29,9 @@ OFILES=\
../8l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lm -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.8 8.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
index ce1512c51..3424f762c 100644
--- a/src/cmd/8c/cgen64.c
+++ b/src/cmd/8c/cgen64.c
@@ -57,7 +57,7 @@ vaddr(Node *n, int a)
int32
hi64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)(n->vconst) & ~0L;
else
return (int32)((uvlong)n->vconst>>32) & ~0L;
@@ -66,7 +66,7 @@ hi64v(Node *n)
int32
lo64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)((uvlong)n->vconst>>32) & ~0L;
else
return (int32)(n->vconst) & ~0L;
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
index 538e3522c..14945052e 100644
--- a/src/cmd/8c/div.c
+++ b/src/cmd/8c/div.c
@@ -120,7 +120,7 @@ sdivgen(Node *l, Node *r, Node *ax, Node *dx)
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
-//print("a=%d i=%ld s=%d m=%lux\n", a, (int32)r->vconst, s, m);
+//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
@@ -141,7 +141,7 @@ udivgen(Node *l, Node *r, Node *ax, Node *dx)
Node nod;
a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (int32)r->vconst, t, s, m);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
index 6caafd258..c422905cd 100644
--- a/src/cmd/8c/list.c
+++ b/src/cmd/8c/list.c
@@ -76,15 +76,27 @@ Pconv(Fmt *fp)
Prog *p;
p = va_arg(fp->args, Prog*);
- if(p->as == ADATA)
- sprint(str, " %A %D/%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
- else if(p->as == ATEXT)
- sprint(str, " %A %D,%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
- else
- sprint(str, " %A %D,%D",
- p->as, &p->from, &p->to);
+ switch(p->as) {
+ case ADATA:
+ sprint(str, "(%L) %A %D/%d,%D",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+
+ case ATEXT:
+ if(p->from.scale) {
+ sprint(str, "(%L) %A %D,%d,%lD",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
+ break;
+
+ default:
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
+ break;
+ }
return fmtstrcpy(fp, str);
}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
index 2b7332d54..a0742807e 100644
--- a/src/cmd/8c/mul.c
+++ b/src/cmd/8c/mul.c
@@ -355,7 +355,7 @@ mulgen1(uint32 v, Node *n)
mulparam(v, p);
found:
-// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
index 837da2d04..6ba07bed2 100644
--- a/src/cmd/8c/reg.c
+++ b/src/cmd/8c/reg.c
@@ -382,7 +382,7 @@ regopt(Prog *p)
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] |
@@ -1031,7 +1031,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -1044,7 +1044,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1054,7 +1054,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1064,7 +1064,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index 1c502f5ff..be48885f8 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -40,7 +40,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
gopcode(OEQ, n->type, n, nodconst(q->val));
patch(p, q->label);
q++;
@@ -52,7 +52,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
i = nc / 2;
r = q+i;
if(debug['W'])
- print("case > %.8lux\n", r->val);
+ print("case > %.8ux\n", r->val);
gopcode(OGT, n->type, n, nodconst(r->val));
sp = p;
gbranch(OGOTO);
@@ -61,7 +61,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
swit1(q, i, def, n);
if(debug['W'])
- print("case < %.8lux\n", r->val);
+ print("case < %.8ux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
}
@@ -501,7 +501,7 @@ zaddr(Biobuf *b, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -515,7 +515,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_LONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -523,10 +525,16 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_LONG)
- w = SZ_LONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else {
+ w = ewidth[v->etype];
+ if(w == 8)
+ w = 4;
+ }
+ if(w < 1 || w > SZ_LONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -536,8 +544,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -558,13 +566,15 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1);
- o = align(o, t, Ael2);
+ o = align(o, t, Ael1, nil);
+ o = align(o, t, Ael2, nil);
break;
}
o = xround(o, w);
+ if(maxalign && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 194599c3a..0dd387d11 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -385,7 +385,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -399,22 +399,22 @@ regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -1403,7 +1403,6 @@ exreg(Type *t)
return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1.
}
- USED(t);
return 0;
}
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
index d2431182f..09cf8d4e3 100644
--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8g
+TARG=8g
HFILES=\
../gc/go.h\
@@ -27,18 +27,9 @@ OFILES=\
reg.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.8 enam.c 8.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../gc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 8fbdc6ee7..875d434fa 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -175,7 +175,7 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
case OCMPLX:
- // TODO compile complex
+ fatal("unexpected complex");
return;
// these call bgen to get a bool value
@@ -230,8 +230,8 @@ cgen(Node *n, Node *res)
cgen(nl, res);
break;
}
- mgen(nl, &n1, res);
tempname(&n2, n->type);
+ mgen(nl, &n1, res);
gmove(&n1, &n2);
gmove(&n2, res);
mfree(&n1);
@@ -392,23 +392,16 @@ uop: // unary
gmove(&n1, res);
return;
-flt: // floating-point. 387 (not SSE2) to interoperate with 6c
+flt: // floating-point. 387 (not SSE2) to interoperate with 8c
nodreg(&f0, nl->type, D_F0);
nodreg(&f1, n->type, D_F0+1);
if(nr != N)
goto flt2;
- if(n->op == OMINUS) {
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- n->op = OMUL;
- goto flt2;
- }
-
// unary
cgen(nl, &f0);
if(n->op != OCONV && n->op != OPLUS)
- gins(foptoas(n->op, n->type, 0), &f0, &f0);
+ gins(foptoas(n->op, n->type, 0), N, N);
gmove(&f0, res);
return;
@@ -525,9 +518,11 @@ agen(Node *n, Node *res)
p2 = nil; // to be patched to panicindex.
w = n->type->width;
if(nr->addable) {
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
+ if(!isconst(nr, CTINT))
tempname(&tmp, types[TINT32]);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ if(!isconst(nr, CTINT)) {
p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
@@ -539,13 +534,16 @@ agen(Node *n, Node *res)
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
} else {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
nr = &tmp;
- agenr(nl, &n3, res);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
@@ -556,7 +554,7 @@ agen(Node *n, Node *res)
// explicit check for nil if array is large enough
// that we might derive too big a pointer.
- if(!isslice(nl->type) && nl->type->width >= unmappedzero) {
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
regalloc(&n4, types[tptr], &n3);
gmove(&n3, &n4);
n4.op = OINDREG;
@@ -571,9 +569,10 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index");
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
@@ -591,13 +590,6 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
nodconst(&n2, types[tptr], v*w);
@@ -614,7 +606,9 @@ agen(Node *n, Node *res)
if(!debug['B'] && !n->etype) {
// check bounds
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR))
+ nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
+ else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -628,8 +622,17 @@ agen(Node *n, Node *res)
ginscall(panicindex, 0);
patch(p1, pc);
}
+
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ p1 = gins(ALEAL, N, &n3);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ p1->from.scale = 1;
+ p1->from.index = n2.val.u.reg;
+ goto indexdone;
+ }
- if(isslice(nl->type)) {
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -649,6 +652,7 @@ agen(Node *n, Node *res)
gmove(&n3, res);
}
+ indexdone:
gmove(&n3, res);
regfree(&n2);
regfree(&n3);
@@ -724,8 +728,14 @@ igen(Node *n, Node *a, Node *res)
{
Node n1;
+ // release register for now, to avoid
+ // confusing tempname.
+ if(res != N && res->op == OREGISTER)
+ reg[res->val.u.reg]--;
tempname(&n1, types[tptr]);
agen(n, &n1);
+ if(res != N && res->op == OREGISTER)
+ reg[res->val.u.reg]++;
regalloc(a, types[tptr], res);
gmove(&n1, a);
a->op = OINDREG;
@@ -768,6 +778,9 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 346647205..1c14dfe47 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 4;
widthptr = 4;
zprog.link = P;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 8a55ffd59..4dcbd4489 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -8,7 +8,6 @@
#include "opt.h"
static Prog *pret;
-static Node *naclnop;
void
compile(Node *fn)
@@ -24,7 +23,6 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
- naclnop = sysfunc("naclnop");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
@@ -64,6 +62,8 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+ setlineno(curfn);
+
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
@@ -85,6 +85,8 @@ compile(Node *fn)
checklabels();
if(nerrors != 0)
goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
@@ -92,21 +94,13 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer) {
- // On Native client, insert call to no-op function
- // to force alignment immediately before call to deferreturn,
- // so that when jmpdefer subtracts 5 from the second CALL's
- // return address and then the return masks off the low bits,
- // we'll back up to the NOPs immediately after the dummy CALL.
- if(strcmp(getgoos(), "nacl") == 0)
- ginscall(naclnop, 0);
- ginscall(deferreturn, 0);
- }
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
@@ -114,12 +108,12 @@ compile(Node *fn)
regopt(ptxt);
}
// fill in argument size
- ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
if(stksize > maxstksize)
maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
if(debug['f'])
@@ -789,25 +783,58 @@ regcmp(const void *va, const void *vb)
static Prog* throwpc;
+// We're only going to bother inlining if we can
+// convert all the arguments to 32 bits safely. Can we?
+static int
+fix64(NodeList *nn, int n)
+{
+ NodeList *l;
+ Node *r;
+ int i;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ r = l->n->right;
+ if(is64(r->type) && !smallintconst(r)) {
+ if(r->op == OCONV)
+ r = r->left;
+ if(is64(r->type))
+ return 0;
+ }
+ l = l->next;
+ }
+ return 1;
+}
+
void
getargs(NodeList *nn, Node *reg, int n)
{
NodeList *l;
+ Node *r;
int i;
throwpc = nil;
l = nn;
for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
+ r = l->n->right;
+ if(is64(r->type)) {
+ if(r->op == OCONV)
+ r = r->left;
+ else if(smallintconst(r))
+ r->type = types[TUINT32];
+ if(is64(r->type))
+ fatal("getargs");
+ }
+ if(!smallintconst(r) && !isslice(r->type)) {
if(i < 3) // AX CX DX
- nodreg(reg+i, l->n->right->type, D_AX+i);
+ nodreg(reg+i, r->type, D_AX+i);
else
reg[i].op = OXXX;
- regalloc(reg+i, l->n->right->type, reg+i);
- cgen(l->n->right, reg+i);
+ regalloc(reg+i, r->type, reg+i);
+ cgen(r, reg+i);
} else
- reg[i] = *l->n->right;
+ reg[i] = *r;
if(reg[i].local != 0)
yyerror("local used");
reg[i].local = l->n->left->xoffset;
@@ -821,44 +848,53 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
- Node *c;
+ Node *c, n1;
+ Type *t;
op = OLE;
if(smallintconst(nl)) {
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AJMP, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
-
// put the constant on the right
op = brrev(op);
c = nl;
nl = nr;
nr = c;
}
-
- gins(optoas(OCMP, types[TUINT32]), nl, nr);
+
+ // Arguments are known not to be 64-bit,
+ // but they might be smaller than 32 bits.
+ // Check if we need to use a temporary.
+ // At least one of the arguments is 32 bits
+ // (the len or cap) so one temporary suffices.
+ n1.op = OXXX;
+ t = types[TUINT32];
+ if(nl->type->width != t->width) {
+ regalloc(&n1, t, nl);
+ gmove(nl, &n1);
+ nl = &n1;
+ } else if(nr->type->width != t->width) {
+ regalloc(&n1, t, nr);
+ gmove(nr, &n1);
+ nr = &n1;
+ }
+ gins(optoas(OCMP, t), nl, nr);
+ if(n1.op != OXXX)
+ regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
throwpc = pc;
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
patch(p1, throwpc);
}
}
@@ -889,6 +925,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -906,6 +944,8 @@ cgen_inline(Node *n, Node *res)
slicearray:
if(!sleasy(res))
goto no;
+ if(!fix64(n->list, 5))
+ goto no;
getargs(n->list, nodes, 5);
// if(hb[3] > nel[1]) goto throw
@@ -988,6 +1028,8 @@ slicearray:
return 1;
sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
@@ -1016,6 +1058,7 @@ sliceslice:
// if(lb[1] > old.nel[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
@@ -1035,6 +1078,7 @@ sliceslice:
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2);
// if(lb[1] > hb[2]) goto throw;
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index 1f4b106f7..e48ad529b 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -642,7 +642,7 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
}
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Sym *e;
int c, d, o, mov, add, loaded;
@@ -739,7 +739,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 6890c683e..8ed7e5564 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -149,6 +149,8 @@ ggloblnod(Node *nam, int32 width)
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
}
void
@@ -165,6 +167,7 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.offset = width;
if(dupok)
p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
}
int
@@ -661,6 +664,11 @@ foptoas(int op, Type *t, int flg)
return AFCOMDP;
case FCASE(OCMP, TFLOAT64, Fpop2):
return AFCOMDPP;
+
+ case FCASE(OMINUS, TFLOAT32, 0):
+ return AFCHS;
+ case FCASE(OMINUS, TFLOAT64, 0):
+ return AFCHS;
}
fatal("foptoas %O %T %#x", op, t, flg);
@@ -707,7 +715,7 @@ gclean(void)
for(i=D_AL; i<=D_DI; i++)
if(reg[i])
- yyerror("reg %R left allocated at %lux", i, regpc[i]);
+ yyerror("reg %R left allocated at %ux", i, regpc[i]);
}
int32
@@ -764,7 +772,7 @@ regalloc(Node *n, Type *t, Node *o)
fprint(2, "registers allocated at\n");
for(i=D_AX; i<=D_DI; i++)
- fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
+ fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
yyerror("out of fixed registers");
goto err;
@@ -1651,7 +1659,7 @@ checkoffset(Addr *a, int canemitcode)
if(a->offset < unmappedzero)
return;
if(!canemitcode)
- fatal("checkoffset %#llx, cannot emit code", a->offset);
+ fatal("checkoffset %#x, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
index 9b3622a6d..edb1ece84 100644
--- a/src/cmd/8g/list.c
+++ b/src/cmd/8g/list.c
@@ -47,24 +47,28 @@ Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
+ char scale[40];
p = va_arg(fp->args, Prog*);
sconsize = 8;
+ scale[0] = '\0';
+ if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
+ snprint(scale, sizeof scale, "%d,", p->from.scale);
switch(p->as) {
default:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%D",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
case ADATA:
sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%lD",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
}
return fmtstrcpy(fp, str);
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 3e57916c7..e1dacf55a 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -612,17 +612,17 @@ brk:
print("\nstats\n");
if(ostats.ncvtreg)
- print(" %4ld cvtreg\n", ostats.ncvtreg);
+ print(" %4d cvtreg\n", ostats.ncvtreg);
if(ostats.nspill)
- print(" %4ld spill\n", ostats.nspill);
+ print(" %4d spill\n", ostats.nspill);
if(ostats.nreload)
- print(" %4ld reload\n", ostats.nreload);
+ print(" %4d reload\n", ostats.nreload);
if(ostats.ndelmov)
- print(" %4ld delmov\n", ostats.ndelmov);
+ print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4ld delmov\n", ostats.nvar);
+ print(" %4d delmov\n", ostats.nvar);
if(ostats.naddr)
- print(" %4ld delmov\n", ostats.naddr);
+ print(" %4d delmov\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -789,6 +789,8 @@ mkvar(Reg *r, Adr *a)
// if they overlaps, disable both
if(overlap(v->offset, v->width, o, w)) {
+ if(debug['R'])
+ print("disable %s\n", v->sym->name);
v->addr = 1;
flag = 1;
}
@@ -821,7 +823,7 @@ mkvar(Reg *r, Adr *a)
v->addr = flag; // funny punning
if(debug['R'])
- print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
+ print("bit=%2d et=%2d w=%d %S %D flag=%d\n", i, et, w, s, a, v->addr);
ostats.nvar++;
bit = blsh(i);
@@ -1378,7 +1380,7 @@ dumpone(Reg *r)
int z;
Bits bit;
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] =
r->set.b[z] |
@@ -1427,14 +1429,14 @@ dumpit(char *str, Reg *r0)
if(r1 != R) {
print(" pred:");
for(; r1 != R; r1 = r1->p2link)
- print(" %.4lud", r1->prog->loc);
+ print(" %.4ud", r1->prog->loc);
print("\n");
}
// r1 = r->s1;
// if(r1 != R) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4lud", r1->prog->loc);
+// print(" %.4ud", r1->prog->loc);
// print("\n");
// }
}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index c17f606e2..0866f05f0 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
enum as
{
@@ -383,8 +384,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -498,6 +499,9 @@ enum
D_CONST2 = D_INDIR+D_INDIR,
D_SIZE, /* 8l internal */
+ D_PCREL,
+ D_GOTOFF,
+ D_GOTREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index 88c7c512b..84976ba18 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -2,15 +2,20 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8l\
+TARG=8l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
+ go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
@@ -18,30 +23,26 @@ OFILES=\
optab.$O\
pass.$O\
pe.$O\
+ prof.$O\
span.$O\
- go.$O\
+ symtab.$O\
+
HFILES=\
l.h\
../8l/8.out.h\
+ ../ld/dwarf.h\
../ld/elf.h\
../ld/macho.h\
../ld/pe.h\
-
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 8.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.8 enam.c 8.out a.out
+CLEANFILES+=enam.c
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index a7f894aa2..cdb5a33e6 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -28,9 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../ld/macho.h"
#include "../ld/pe.h"
@@ -38,7 +41,6 @@
char linuxdynld[] = "/lib/ld-linux.so.2";
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-uint32 symdatva = SYMDATVA;
int32
entryvalue(void)
@@ -52,15 +54,8 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
@@ -103,134 +98,13 @@ vputl(uvlong l)
lputl(l);
}
-void
-strnput(char *s, int n)
-{
- for(; *s && n > 0; s++) {
- cput(*s);
- n--;
- }
- while(n > 0) {
- cput(0);
- n--;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > sizeof(p->to.scon))
- m = sizeof(p->to.scon);
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- memmove(p->to.scon, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT) {
- if(HEADTYPE == 8)
- return addr - INITDAT + rnd(HEADR+textsize, 4096);
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
- }
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
diag("datoff %#llx", addr);
return 0;
}
@@ -252,6 +126,10 @@ enum {
ElfStrGosymtab,
ElfStrGopclntab,
ElfStrShstrtab,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
NElfStr
};
@@ -273,26 +151,424 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rel, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_386_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_386_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ case 256 + R_386_GOT32:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_GOTOFF;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_386_GOTOFF:
+ r->type = D_GOTOFF;
+ return;
+
+ case 256 + R_386_GOTPC:
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ return;
+
+ case 256 + R_386_32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ r->type = D_PCREL;
+ return;
+
+ case 512 + MACHO_FAKE_GOTPCREL:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ addgotsym(targ);
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ r->type = D_PCREL;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, s, r->off);
+ adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ return;
+ }
+ if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation
+ // that is too much bother to deal with.
+ // Instead, interpret the C declaration
+ // void *_Cvar_stderr = &stderr;
+ // as making _Cvar_stderr the name of a GOT entry
+ // for stderr. This is separate from the usual GOT entry,
+ // just in case the C code assigns to the variable,
+ // and of course it only works for single pointers,
+ // but we only need to support cgo and that's all it needs.
+ adddynsym(targ);
+ got = lookup(".got", 0);
+ s->type = got->type | SSUB;
+ s->outer = got;
+ s->sub = got->sub;
+ got->sub = s;
+ s->value = got->size;
+ adduint32(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushl got+4
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addaddrplus(plt, got, 4);
+
+ // jmp *got+8
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, 8);
+
+ // zero pad
+ adduint32(plt, 0);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint32(got, 0);
+ adduint32(got, 0);
+ }
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ switch(r->type) {
+ case D_CONST:
+ *val = r->add;
+ return 0;
+ case D_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ return 0;
+ }
+ return -1;
+}
+
+static void
+addpltsym(Sym *s)
+{
+ Sym *plt, *got, *rel;
+
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rel = lookup(".rel.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushl $x
+ adduint8(plt, 0x68);
+ adduint32(plt, rel->size);
+
+ // jmp .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rel
+ addaddrplus(rel, got, got->size-4);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // Same laziness as in 6l.
+
+ Sym *plt;
+
+ plt = lookup(".plt", 0);
+
+ addgotsym(s);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rel;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint32(got, 0);
+
+ if(iself) {
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, got, s->got);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+ } else if(HEADTYPE == 6) { // Mach-O
+ adduint32(lookup(".linkedit.got", 0), s->dynid);
+ } else {
+ diag("addgotsym: unsupported binary format");
+ }
+}
+
+void
+adddynsym(Sym *s)
+{
+ Sym *d, *str;
+ int t;
+ char *name;
+
+ if(s->dynid >= 0)
+ return;
+
+ if(s->dynimpname == nil)
+ diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+
+ /* name */
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint32(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size */
+ adduint32(d, 0);
+
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+ adduint8(d, 0);
+
+ /* shndx */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-O symbol nlist32
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/12;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ adduint16(d, 0); // desc
+ adduint32(d, 0); // value
+ } else {
+ diag("adddynsym: unsupported binary format");
+ }
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == 6) { // Mach-O
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".elfdata");
+ addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -305,6 +581,8 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+ elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* interpreter string */
s = lookup(".interp", 0);
@@ -315,13 +593,14 @@ doelf(void)
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF32SYMSIZE;
+ s->size += ELF32SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->reachable = 1;
s->type = SELFDATA;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -332,88 +611,36 @@ doelf(void)
/* global offset table */
s = lookup(".got", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* got.plt - ??? */
+ /* got.plt */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
+ s = lookup(".rel.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
- /*
- * relocation entries for dynimport symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rel", 0);
- addaddr(d, s);
- adduint32(d, ELF32_R_INFO(nsym, R_386_32));
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* value */
- if(!s->dynexport)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
+ elfsetupplt();
- elfdynhash(nsym);
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -424,6 +651,10 @@ doelf(void)
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_REL);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -450,155 +681,52 @@ phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
void
asmb(void)
{
- Prog *p;
int32 v, magic;
int a, dynsym;
uint32 va, fo, w, symo, startva, machlink;
- uchar *op1;
- ulong expectpc;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- curp = p;
- if(HEADTYPE == 8) {
- // native client
- expectpc = p->pc;
- p->pc = pc;
- asmins(p);
- if(p->pc != expectpc) {
- Bflush(&bso);
- diag("phase error %lux sb %lux in %s", p->pc, expectpc, TNAME);
- }
- while(pc < p->pc) {
- cput(0x90); // nop
- pc++;
- }
- }
- if(p->pc != pc) {
- Bflush(&bso);
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- if(HEADTYPE != 8) {
- asmins(p);
- if(pc != p->pc) {
- Bflush(&bso);
- diag("asmins changed pc %lux sb %lux in %s", p->pc, pc, TNAME);
- }
- }
- if(cbc < sizeof(and))
- cflush();
- a = (andptr - and);
-
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1 & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- }
- if(dlm) {
- if(p->as == ATEXT)
- reloca = nil;
- else if(reloca != nil)
- diag("reloc failure: %P", curp);
- }
- memmove(cbp, and, a);
- cbp += a;
- pc += a;
- cbc -= a;
- }
- if(HEADTYPE == 8) {
- while(pc < INITDAT) {
- cput(0xf4); // hlt
- pc++;
- }
- }
- cflush();
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
- switch(HEADTYPE) {
- default:
- if(iself)
- goto Elfseek;
- diag("unknown header type %d", HEADTYPE);
- case 0:
- seek(cout, rnd(HEADR+textsize, 8192), 0);
- break;
- case 1:
- textsize = rnd(HEADR+textsize, 4096)-HEADR;
- seek(cout, textsize+HEADR, 0);
- break;
- case 2:
- seek(cout, HEADR+textsize, 0);
- break;
- case 3:
- case 4:
- seek(cout, HEADR+rnd(textsize, INITRND), 0);
- break;
- case 6:
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
- break;
- case 8:
- // Native Client only needs to round
- // text segment file address to 4096 bytes,
- // but text segment memory address rounds
- // to INITRND (65536).
- v = rnd(HEADR+textsize, 4096);
- seek(cout, v, 0);
- break;
- Elfseek:
- case 10:
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
- break;
- }
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
if(debug['v'])
Bprint(&bso, "%5.2f datblk\n", cputime());
Bflush(&bso);
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
- if(datsize-v > sizeof(buf)-Dbufslop)
- datblk(v, sizeof(buf)-Dbufslop);
- else
- datblk(v, datsize-v);
- }
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
machlink = 0;
if(HEADTYPE == 6)
machlink = domacholink();
+ if(iself) {
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 1;
+ if(!debug['d'])
+ elftextsh += 10;
+ }
+
symsize = 0;
spsize = 0;
lcsize = 0;
symo = 0;
if(!debug['s']) {
+ // TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
@@ -607,53 +735,38 @@ asmb(void)
if(iself)
goto Elfsym;
case 0:
- seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, 8192)+segdata.filelen, 0);
break;
case 1:
- seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
break;
case 2:
- seek(cout, HEADR+textsize+datsize, 0);
+ seek(cout, HEADR+segtext.filelen+segdata.filelen, 0);
break;
case 3:
case 4:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.filelen+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
Elfsym:
- case 10:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
+ case 10:
+ // TODO(brainman): not sure what symo meant to be, but it is not used for Windows PE for now anyway
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
+ }
+ if(HEADTYPE != 10 && !debug['s']) {
+ seek(cout, symo, 0);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
}
- seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
- if(debug['v'])
- Bprint(&bso, "%5.2f sp\n", cputime());
- Bflush(&bso);
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(HEADTYPE == 10 || (iself && !debug['s']))
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
- seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- }
- else if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f headr\n", cputime());
@@ -666,17 +779,17 @@ asmb(void)
case 0: /* garbage */
lput(0x160L<<16); /* magic and sections */
lput(0L); /* time and date */
- lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
lput(symsize); /* nsyms */
lput((0x38L<<16)|7L); /* size of optional hdr and flags */
lput((0413<<16)|0437L); /* magic and version */
- lput(rnd(HEADR+textsize, 4096)); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(entryvalue()); /* va of entry */
lput(INITTEXT-HEADR); /* va of base of text */
- lput(INITDAT); /* va of base of data */
- lput(INITDAT+datsize); /* va of base of bss */
+ lput(segdata.vaddr); /* va of base of data */
+ lput(segdata.vaddr+segdata.filelen); /* va of base of bss */
lput(~0L); /* gp reg mask */
lput(0L);
lput(0L);
@@ -698,19 +811,19 @@ asmb(void)
* a.out header
*/
lputl(0x10b); /* magic, version stamp */
- lputl(rnd(textsize, INITRND)); /* text sizes */
- lputl(datsize); /* data sizes */
- lputl(bsssize); /* bss sizes */
+ lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
+ lputl(segdata.filelen); /* data sizes */
+ lputl(segdata.len - segdata.filelen); /* bss sizes */
lput(entryvalue()); /* va of entry */
lputl(INITTEXT); /* text start */
- lputl(INITDAT); /* data start */
+ lputl(segdata.vaddr); /* data start */
/*
* text section header
*/
s8put(".text");
lputl(HEADR); /* pa */
lputl(HEADR); /* va */
- lputl(textsize); /* text size */
+ lputl(segtext.filelen); /* text size */
lputl(HEADR); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -720,10 +833,10 @@ asmb(void)
* data section header
*/
s8put(".data");
- lputl(INITDAT); /* pa */
- lputl(INITDAT); /* va */
- lputl(datsize); /* data size */
- lputl(HEADR+textsize); /* file offset */
+ lputl(segdata.vaddr); /* pa */
+ lputl(segdata.vaddr); /* va */
+ lputl(segdata.filelen); /* data size */
+ lputl(HEADR+segtext.filelen); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
@@ -732,9 +845,9 @@ asmb(void)
* bss section header
*/
s8put(".bss");
- lputl(INITDAT+datsize); /* pa */
- lputl(INITDAT+datsize); /* va */
- lputl(bsssize); /* bss size */
+ lputl(segdata.vaddr+segdata.filelen); /* pa */
+ lputl(segdata.vaddr+segdata.filelen); /* va */
+ lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -747,20 +860,18 @@ asmb(void)
lputl(0); /* pa */
lputl(0); /* va */
lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+textsize+datsize); /* file offset */
- lputl(HEADR+textsize+datsize); /* offset of syms */
- lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
+ lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x200); /* flags comment only */
break;
case 2: /* plan9 */
magic = 4*11*11+7;
- if(dlm)
- magic |= 0x80000000;
lput(magic); /* magic */
- lput(textsize); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(segtext.filelen); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(spsize); /* sp offsets */
@@ -771,7 +882,7 @@ asmb(void)
break;
case 4:
/* fake MS-DOS .EXE */
- v = rnd(HEADR+textsize, INITRND)+datsize;
+ v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
wputl(0x5A4D); /* 'MZ' */
wputl(v % 512); /* bytes in last page */
wputl(rnd(v, 512)/512); /* total number of pages */
@@ -793,34 +904,31 @@ asmb(void)
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
Elfput:
/* elf 386 */
- if(HEADTYPE == 8 || HEADTYPE == 11)
+ if(HEADTYPE == 11)
debug['d'] = 1;
eh = getElfEhdr();
fo = HEADR;
startva = INITTEXT - HEADR;
va = startva + fo;
- w = textsize;
+ w = segtext.filelen;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
- /* program header info - but not on native client */
- pph = nil;
- if(HEADTYPE != 8) {
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
- }
+ /* program header info */
+ pph = newElfPhdr();
+ pph->type = PT_PHDR;
+ pph->flags = PF_R + PF_X;
+ pph->off = eh->ehsize;
+ pph->vaddr = INITTEXT - HEADR + pph->off;
+ pph->paddr = INITTEXT - HEADR + pph->off;
+ pph->align = INITRND;
if(!debug['d']) {
/* interpreter */
@@ -843,51 +951,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- if(HEADTYPE != 8) { // Include header, but not on Native Client.
- va -= fo;
- w += fo;
- fo = 0;
- }
- ph->vaddr = va;
- ph->paddr = va;
- ph->off = fo;
- ph->filesz = w;
- ph->memsz = INITDAT - va;
- ph->align = INITRND;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = INITDAT;
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s'] && HEADTYPE != 8 && HEADTYPE != 11) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -921,6 +986,22 @@ asmb(void)
sh->flags = SHF_ALLOC;
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRelPlt]);
+ sh->type = SHT_REL;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32RELSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rel.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
@@ -968,80 +1049,27 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
- fo = HEADR;
- va = startva + fo;
- w = textsize;
-
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = 4;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
+ if(elftextsh != eh->shnum)
+ diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
- sh = newElfShdr(elfstr[ElfStrGosymcounts]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
-
sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
-
- fo += w;
- w = lcsize;
+ shsym(sh, lookup("symtab", 0));
sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
+ shsym(sh, lookup("pclntab", 0));
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -1058,11 +1086,6 @@ asmb(void)
eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
switch(HEADTYPE) {
- case 8:
- eh->ident[EI_OSABI] = ELFOSABI_NACL;
- eh->ident[EI_ABIVERSION] = 7;
- eh->flags = 0x200000; // aligned mod 32
- break;
case 9:
eh->ident[EI_OSABI] = 9;
break;
@@ -1113,215 +1136,16 @@ cflush(void)
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
-void
-datblk(int32 s, int32 n)
+/* Current position in file */
+vlong
+cpos(void)
{
- Prog *p;
- char *cast;
- int32 l, fl, j;
- int i, c;
- Adr *a;
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
- continue;
- i = -l;
- l = 0;
- }
-
- curp = p;
- if(!a->sym->reachable)
- diag("unreachable symbol in datblk - %s", a->sym->name);
- if(a->sym->type == SMACHO)
- continue;
-
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization");
- break;
- }
- }
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.scon[i];
- l++;
- }
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- }
- break;
- }
- }
-
- write(cout, buf.dbuf, n);
- if(!debug['a'])
- return;
-
- /*
- * a second pass just to print the asm
- */
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l < 0 || l >= n)
- continue;
-
- c = a->scale;
- i = 0;
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
-
- case D_SCONST:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 2:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 4:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
- }
- }
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
int32
@@ -1338,3 +1162,71 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ case SMACHO:
+ case SMACHOGOT:
+ case SWINDOWS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
+ }
+ }
+ }
+
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
+ continue;
+
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
index c8c058684..0bf6f151f 100644
--- a/src/cmd/8l/doc.go
+++ b/src/cmd/8l/doc.go
@@ -29,8 +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)
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-L dir1 -L dir2
+ Search for libraries (package files) in dir1, dir2, etc.
The default is the single location $GOROOT/pkg/$GOOS_386.
-r dir1:dir2:...
Set the dynamic linker search path when using ELF.
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 495c40d64..daede8879 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -44,7 +44,7 @@ enum
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define TNAME (curtext?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
@@ -55,6 +55,7 @@ typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -66,11 +67,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
uchar index;
char scale;
@@ -83,18 +80,25 @@ struct Adr
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int32 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
int32 pc;
+ int32 spadj;
int32 line;
short as;
char width; /* fake for DATA */
@@ -103,8 +107,10 @@ struct Prog
uchar mark; /* work on these */
uchar back;
uchar bigjmp;
-
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +121,39 @@ struct Auto
};
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar special;
int32 value;
int32 size;
int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
+ int32 dynid;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in sub list
+ Sym* outer; // container of sub
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
struct Optab
{
@@ -146,23 +166,28 @@ struct Optab
enum
{
Sxxx,
-
+
+ /* order here is order in output file */
STEXT,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SWINDOWS,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
+ SDYNIMPORT,
- SMACHO, /* pointer to mach-o imported symbol */
-
- SFIXED,
- SELFDATA,
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
NHASH = 10007,
NHUNK = 100000,
@@ -240,9 +265,6 @@ enum
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
};
EXTERN union
@@ -266,12 +288,11 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN int32 INITDAT;
EXTERN int32 INITRND;
EXTERN int32 INITTEXT;
+EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int32 casepc;
EXTERN int cbc;
EXTERN char* cbp;
@@ -279,22 +300,17 @@ EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN int32 datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN int32 elfdatsize;
-EXTERN int32 dynptrsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
+EXTERN Sym* etextp;
EXTERN Prog* firstp;
-EXTERN int xrefresolv;
EXTERN uchar ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar and[100];
EXTERN char reg[D_NONE];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int maxop;
EXTERN int nerrors;
@@ -304,30 +320,22 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
+EXTERN Sym* textp;
EXTERN int32 textsize;
-EXTERN int32 textpad;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int tlsoffset;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-EXTERN Adr* reloca;
-EXTERN int doexp, dlm;
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
-
-#define UP (&undefp)
+EXTERN int elftextsh;
extern Optab optab[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
@@ -336,29 +344,23 @@ Prog* appendp(Prog*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
int32 atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
-void datblk(int32, int32);
void diag(char*, ...);
void dodata(void);
void doelf(void);
-void doinit(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
int32 entryvalue(void);
-void export(void);
void follow(void);
-void import(void);
+void instinit(void);
void listinit(void);
Sym* lookup(char*, int);
void lput(int32);
@@ -366,26 +368,20 @@ void lputl(int32);
void vputl(uvlong);
void strnput(char*, int);
void main(int, char*[]);
-void mkfwd(void);
void* mal(uint32);
-Prog* newdata(Sym*, int, int, int);
-Prog* newtext(Prog*, Sym*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
int relinv(int);
-int32 reuse(Prog*, Sym*);
int32 rnd(int32, int32);
void s8put(char*);
void span(void);
void undef(void);
-int32 vaddr(Adr*);
int32 symaddr(Sym*);
void wput(ushort);
void wputl(ushort);
void xdefine(char*, int, int32);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
+
uint32 machheadr(void);
vlong addaddr(Sym *s, Sym *t);
vlong addsize(Sym *s, Sym *t);
@@ -410,3 +406,9 @@ void deadcode(void);
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "A" int
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 4
+};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index a5dbba7f8..4e199d767 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -40,6 +42,7 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
static Prog *bigP;
@@ -47,7 +50,6 @@ static Prog *bigP;
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
@@ -55,23 +57,23 @@ Pconv(Fmt *fp)
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- sprint(str, "(%d) %A %D,%d,%D",
+ fmtprint(fp, "(%d) %A %D,%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
- sprint(str, "(%d) %A %D,%D",
+ fmtprint(fp, "(%d) %A %D,%D",
p->line, p->as, &p->from, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- sprint(str, "(%d) %A %D/%d,%D",
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -102,15 +104,15 @@ Dconv(Fmt *fp)
i = a->type;
if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
- sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
+ snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
else
- sprint(str, "(%R)", i-D_INDIR);
+ snprint(str, sizeof str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
- sprint(str, "%R", i);
+ snprint(str, sizeof str, "%R", i);
break;
case D_NONE:
@@ -120,54 +122,54 @@ Dconv(Fmt *fp)
case D_BRANCH:
if(bigP != P && bigP->pcond != P)
if(a->sym != S)
- sprint(str, "%lux+%s", bigP->pcond->pc,
+ snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
a->sym->name);
else
- sprint(str, "%lux", bigP->pcond->pc);
+ snprint(str, sizeof str, "%ux", bigP->pcond->pc);
else
- sprint(str, "%ld(PC)", a->offset);
+ snprint(str, sizeof str, "%d(PC)", a->offset);
break;
case D_EXTERN:
- sprint(str, "%s+%ld(SB)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
break;
case D_STATIC:
- sprint(str, "%s<%d>+%ld(SB)", xsymname(a->sym),
+ snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
a->sym->version, a->offset);
break;
case D_AUTO:
- sprint(str, "%s+%ld(SP)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
break;
case D_PARAM:
if(a->sym)
- sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
else
- sprint(str, "%ld(FP)", a->offset);
+ snprint(str, sizeof str, "%d(FP)", a->offset);
break;
case D_CONST:
- sprint(str, "$%ld", a->offset);
+ snprint(str, sizeof str, "$%d", a->offset);
break;
case D_CONST2:
- sprint(str, "$%ld-%ld", a->offset, a->offset2);
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
break;
case D_FCONST:
- sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
- sprint(str, "$\"%S\"", a->scon);
+ snprint(str, sizeof str, "$\"%S\"", a->scon);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
- sprint(str, "$%D", a);
+ snprint(str, sizeof str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
@@ -316,19 +318,48 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uchar *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uchar*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n; i++)
+ fmtprint(&fmt, "%.2ux", *p++);
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
if(nerrors > 20) {
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 1a3ecec1d..18b2112fe 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -28,11 +28,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/dwarf.h"
#include "../ld/pe.h"
#include <ar.h>
@@ -52,32 +55,12 @@ char *thestring = "386";
* -H4 -Tx -Rx is fake MS-DOS .EXE
* -H6 -Tx -Rx is Apple Mach-O
* -H7 -Tx -Rx is Linux ELF32
- * -H8 -Tx -Rx is Google Native Client
+ * -H8 -Tx -Rx was Google Native Client
* -H9 -Tx -Rx is FreeBSD ELF32
+ * -H10 -Tx -Rx is MS Windows PE
+ * -H11 -Tx -Rx is tiny (os image)
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else{
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
void
usage(void)
{
@@ -88,7 +71,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -152,9 +135,6 @@ main(int argc, char *argv[])
if(strcmp(goos, "darwin") == 0)
HEADTYPE = 6;
else
- if(strcmp(goos, "nacl") == 0)
- HEADTYPE = 8;
- else
if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9;
else
@@ -164,6 +144,9 @@ main(int argc, char *argv[])
if(strcmp(goos, "tiny") == 0)
HEADTYPE = 11;
else
+ if(strcmp(goos, "plan9") == 0)
+ HEADTYPE = 2;
+ else
print("goos is not known: %s\n", goos);
}
@@ -208,7 +191,7 @@ main(int argc, char *argv[])
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = 4096;
+ INITRND = 1;
break;
case 3: /* MS-DOS .COM */
HEADR = 0;
@@ -229,7 +212,7 @@ main(int argc, char *argv[])
INITRND = 4;
HEADR += (INITTEXT & 0xFFFF);
if(debug['v'])
- Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
+ Bprint(&bso, "HEADR = 0x%d\n", HEADR);
break;
case 6: /* apple MACH */
/*
@@ -249,7 +232,7 @@ main(int argc, char *argv[])
case 7: /* elf32 executable */
case 9:
/*
- * Linux ELF uses TLS offsets negative from %gs.
+ * ELF uses TLS offsets negative from %gs.
* Translate 0(GS) and 4(GS) into -8(GS) and -4(GS).
* Also known to ../../pkg/runtime/linux/386/sys.s
* and ../../libcgo/linux_386.c.
@@ -264,30 +247,15 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case 8: /* native client elf32 executable */
- elfinit();
- HEADR = 4096;
- if(INITTEXT == -1)
- INITTEXT = 0x20000;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 65536;
-
- // 512 kB of address space for closures.
- // (Doesn't take any space in the binary file.)
- // Closures are 64 bytes each, so this is 8,192 closures.
- textpad = 512*1024;
- break;
case 10: /* PE executable */
peinit();
- HEADR = PERESERVE;
+ HEADR = PEFILEHEADR;
if(INITTEXT == -1)
- INITTEXT = PEBASE+0x1000;
+ INITTEXT = PEBASE+PESECTHEADR;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = PEALIGN;
+ INITRND = PESECTALIGN;
break;
case 11:
tlsoffset = 0;
@@ -302,68 +270,14 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: %d", i);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
@@ -373,49 +287,25 @@ main(int argc, char *argv[])
zprg.from.scale = 1;
zprg.to = zprg.from;
- pcstr = "%.6lux ";
+ pcstr = "%.6ux ";
nuxiinit();
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
-
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- errorexit();
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- import();
- HEADTYPE = 2;
- INITTEXT = INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
+ if(HEADTYPE == 10)
+ dope();
dostkoff();
if(debug['p'])
if(debug['1'])
@@ -423,14 +313,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
- if(HEADTYPE == 10)
- dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%d symbols\n", nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
@@ -439,8 +333,19 @@ main(int argc, char *argv[])
errorexit();
}
-void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = Bgetc(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
@@ -465,7 +370,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
a->sym = S;
if(t & T_SYM)
- a->sym = h[Bgetc(f)];
+ a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
a->ieee.h = Bget4(f);
@@ -479,7 +384,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
a->type = Bgetc(f);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
t = a->type;
if(t == D_INDIR+D_GS)
@@ -526,7 +431,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -534,7 +439,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int32 eof;
char *name, *x;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -591,7 +498,7 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures"
- "%lux(%s) and %lux(%s) for %s",
+ "%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
@@ -599,6 +506,8 @@ loop:
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -613,6 +522,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -623,9 +533,9 @@ loop:
p->back = 2;
p->ft = 0;
p->tt = 0;
- zaddr(f, &p->from, h);
+ zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->to, h);
if(debug['W'])
print("%P\n", p);
@@ -647,10 +557,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -659,89 +569,41 @@ loop:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
goto loop;
- case ADYNT:
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->from.scale = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(p->from.sym == S)
- break;
-
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- goto data;
-
- case AINIT:
- if(p->from.sym == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- goto data;
-
case ADATA:
- data:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->link = P;
+ savedata(s, p);
+ unmal(p, sizeof *p);
goto loop;
case AGOK:
@@ -751,9 +613,9 @@ loop:
case ATEXT:
s = p->from.sym;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
@@ -761,13 +623,19 @@ loop:
diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ s->text = p;
+ cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
@@ -775,7 +643,10 @@ loop:
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AFMOVF:
@@ -791,24 +662,12 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -829,25 +688,14 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
+ sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -859,13 +707,18 @@ loop:
default:
if(skip)
nopout(p);
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ goto loop;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
goto loop;
}
goto loop;
@@ -905,153 +758,3 @@ appendp(Prog *q)
p->line = q->line;
return p;
}
-
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
-
- if(p->from.scale & NOPROF) { /* dont profile */
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index 5b7be692e..fceab785d 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -696,8 +696,8 @@ Optab optab[] =
{ AFYL2X, ynone, Px, 0xd9, 0xf1 },
{ AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
{ AEND },
- { ADYNT },
- { AINIT },
+ { ADYNT_ },
+ { AINIT_ },
{ ASIGNAME },
{ ACMPXCHGB, yrb_mb, Pm, 0xb0 },
{ ACMPXCHGL, yrl_ml, Pm, 0xb1 },
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index ace640d22..6e387b0b5 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -28,9 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
+static void xfol(Prog*, Prog**);
+
// see ../../pkg/runtime/proc.c:/StackGuard
enum
{
@@ -38,138 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%ld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 4);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->size = t;
- s->value = t;
- if(t > MINSIZ)
- continue;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 4);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'] || HEADTYPE == 8)
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -186,19 +58,53 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -207,46 +113,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
-
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -259,8 +150,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -268,14 +159,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -284,14 +174,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -299,7 +197,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -339,28 +237,6 @@ relinv(int a)
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -377,116 +253,106 @@ patch(void)
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(HEADTYPE == 10) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x2C(FS), 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) {
- q = appendp(p);
- q->from = p->from;
- q->from.type += p->to.type-D_GS;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2C;
+ 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 0x2C(FS), 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) {
+ 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 = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2C;
+ }
}
- }
- if(p->as == ATEXT)
- curtext = p;
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
+ if(HEADTYPE == 7) { // Linux
+ // Running binaries under Xen requires using
+ // MOVL 0(GS), reg
+ // and then off(reg) instead of saying off(GS) directly
+ // when the offset is negative.
+ if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ 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 = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
}
- p->to.type = D_BRANCH;
}
- }
- if(p->to.type != D_BRANCH || p->pcond == UP)
- continue;
- c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
+ if(HEADTYPE == 2) { // Plan 9
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset += 0xdfffefc0;
+ }
+ }
+ if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
+ s = p->to.sym;
+ if(s) {
+ if(debug['c'])
+ Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+ if((s->type&~SSUB) != STEXT) {
+ /* diag prints TNAME first */
+ diag("undefined: %s", s->name);
+ s->type = STEXT;
+ s->value = vexit;
+ continue; // avoid more error messages
+ }
+ if(s->text == nil)
+ continue;
+ p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
+ }
+ }
+ if(p->to.type != D_BRANCH)
continue;
+ c = p->to.offset;
+ for(q = cursym->text; q != P;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
- if(c == q->pc)
- break;
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s\n%P", TNAME, p);
- p->to.type = D_NONE;
+ if(q == P) {
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
}
- p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->p != nil)
+ continue;
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
+ for(p = cursym->text; p != P; p = p->link) {
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
}
}
}
@@ -513,286 +379,221 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome;
+ int a;
Prog *pmorestack;
Sym *symmorestack;
pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symmorestack) {
- pmorestack = p;
- p->from.scale |= NOSPLIT;
- break;
- }
- }
- }
- if(pmorestack == P)
+ if(symmorestack->type != STEXT)
diag("runtime.morestack not defined");
+ else {
+ pmorestack = symmorestack->text;
+ symmorestack->text->from.scale |= NOSPLIT;
+ }
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if(pmorestack != P)
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ switch(HEADTYPE) {
+ case 10: // Windows
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2c;
+ p->to.type = D_CX;
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ break;
+
+ case 7: // Linux
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
+ break;
+
+ case 2: // Plan 9
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset = 0xdfffefc0;
+ p->to.type = D_CX;
+ break;
+
+ default:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
}
- break;
- }
- }
- autoffset = 0;
- deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if(pmorestack != P)
- if(!(p->from.scale & NOSPLIT)) {
- p = appendp(p); // load g into CX
- if(HEADTYPE == 10) {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2c;
- p->to.type = D_CX;
+ if(debug['K']) {
+ // 8l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info.
+ p = appendp(p);
+ p->as = ACMPL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 4;
+ p->to.type = D_SP;
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- } else {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
+ p = appendp(p);
+ p->as = AJCC;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
+ p->as = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // large stack
p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- }
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
+ p->to.type = D_AX;
- // common
p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- p = appendp(p); // save frame size in DX
- p->as = AMOVL;
- 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)
- p->from.offset = (autoffset+160) & ~7LL;
-
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = curtext->to.offset2;
-
+ // common
p = appendp(p);
- p->as = ACALL;
+ p->as = AJHI;
p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
+ p->to.offset = 4;
+ q = p;
}
- if(q != P)
- q->pcond = p->link;
+ p = appendp(p); // save frame size in DX
+ p->as = AMOVL;
+ 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)
+ p->from.offset = (autoffset+160) & ~7LL;
+
+ p = appendp(p); // save arg size in AX
+ p->as = AMOVL;
+ p->to.type = D_AX;
+ p->from.type = D_CONST;
+ p->from.offset = cursym->text->to.offset2;
+
+ p = appendp(p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack;
+ p->to.sym = symmorestack;
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
- }
- deltasp = autoffset;
- }
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
}
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
- q = p;
p = appendp(p);
- p->as = ARET;
-
- q->as = AADJSP;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+
+ for(; p != P; p = p->link) {
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ q = p;
+ p = appendp(p);
+ p->as = ARET;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ }
}
- continue;
-
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
-
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
}
}
@@ -843,176 +644,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
- diag("%s: not defined", s->name);
-}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
+ diag("%s(%d): not defined", s->name, s->version);
}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
new file mode 100644
index 000000000..4e95fad79
--- /dev/null
+++ b/src/cmd/8l/prof.c
@@ -0,0 +1,173 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.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.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0 // TODO(rsc)
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index 99ba279da..66a843b23 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -28,29 +28,28 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
+static int32 vaddr(Adr*, Reloc*);
+
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v, c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -65,293 +64,186 @@ span(void)
p->as = ANOP;
}
}
-
+
n = 0;
-start:
- do{
- again = 0;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping - %d\n", textsize);
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
+
+ asmins(p);
+ p->pc = c;
+ m = andptr-and;
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ diag("span must be looping");
errorexit();
}
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- if(HEADTYPE == 8)
- c = (c+31)&~31;
- }
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- if(n == 0 || HEADTYPE == 8 || p->to.type == D_BRANCH) {
- if(HEADTYPE == 8)
- p->pc = c;
- asmins(p);
- m = andptr-and;
- if(p->mark != m)
- again = 1;
- p->mark = m;
- }
- if(HEADTYPE == 8) {
- c = p->pc + p->mark;
- } else {
- p->pc = c;
- c += p->mark;
- }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
}
- textsize = c;
- n++;
- }while(again);
-
- if(INITRND) {
- INITDAT = rnd(c+textpad, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %lux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, int32 v)
+span(void)
{
- Sym *s;
-
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ Prog *p, *q;
+ int32 v;
+ int n;
-void
-putsymb(char *s, int t, int32 v, int ver, Sym *go)
-{
- int i, f;
- vlong gv;
-
- if(t == 'f')
- s++;
- lput(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- sysfatal("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- lput(gv);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
- symsize += 4 + 1 + i+1 + 4;
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8lux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8lux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8lux %s\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-asmsym(void)
+xdefine(char *p, int t, int32 v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version, 0);
-
- for(h=0; h<NHASH; h++)
- for(s=hash[h]; s!=S; s=s->link)
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'B', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SFIXED:
- putsymb(s->name, 'B', s->value, s->version, s->gotype);
- continue;
-
- case SFILE:
- putsymb(s->name, 'f', s->value, s->version, 0);
- continue;
- }
- for(p=textp; p!=P; p=p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
-
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0, 0);
- else
- if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0, 0);
-
- if(!s->reachable)
- continue;
-
- putsymb(s->name, 'T', s->value, s->version, s->gotype);
-
- /* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmlc(void)
+instinit(void)
{
- int32 oldpc, oldlc;
- Prog *p;
- int32 v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['L'])
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- continue;
- }
- if(debug['L'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['L'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['L']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
+ int i;
+
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
}
- lcsize++;
- }
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+ maxop = i;
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
}
- if(debug['v'] || debug['L'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
}
int
@@ -506,11 +398,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -525,10 +417,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -564,7 +456,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d,%d,%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -572,10 +464,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -583,24 +471,40 @@ put4(int32 v)
andptr += 4;
}
+static void
+relput4(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
+ put4(v);
+}
+
int32
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-int32
-vaddr(Adr *a)
+static int32
+vaddr(Adr *a, Reloc *r)
{
int t;
int32 v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -611,30 +515,18 @@ vaddr(Adr *a)
case D_EXTERN:
s = a->sym;
if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- default:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
+ if(!s->reachable)
+ sysfatal("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->off = -1;
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
}
return v;
@@ -644,118 +536,127 @@ void
asmand(Adr *a, int r)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR && t < 2*D_INDIR) {
- t -= D_INDIR;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
return;
}
- switch(t) {
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_F0+7) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(a->type) {
default:
goto bad;
case D_STATIC:
case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
+ t = D_NONE;
+ v = vaddr(a, &rel);
break;
case D_AUTO:
case D_PARAM:
- aa.type = D_SP+D_INDIR;
+ t = D_SP;
break;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmand(&aa, r);
- return;
- }
- if(t >= D_AL && t <= D_F0+7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(t >= D_INDIR && t < 2*D_INDIR) {
+ scale = 1;
+ } else
t -= D_INDIR;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
+
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ if(t == D_SP) {
+ if(v == 0 && rel.siz == 0) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- put4(v);
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmand(&aa, r);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -921,22 +822,6 @@ subreg(Prog *p, int from, int to)
print("%P\n", p);
}
-// nacl RET:
-// POPL BX
-// ANDL BX, $~31
-// JMP BX
-uchar naclret[] = { 0x5b, 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl JMP BX:
-// ANDL BX, $~31
-// JMP BX
-uchar nacljmpbx[] = { 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl CALL BX:
-// ANDL BX, $~31
-// CALL BX
-uchar naclcallbx[] = { 0x83, 0xe3, ~31, 0xff, 0xd3 };
-
void
doasm(Prog *p)
{
@@ -945,6 +830,10 @@ doasm(Prog *p)
uchar *t;
int z, op, ft, tt;
int32 v, pre;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
pre = prefixof(&p->from);
if(pre)
@@ -990,7 +879,7 @@ found:
case Pb: /* botch */
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
switch(t[2]) {
default:
@@ -1001,12 +890,6 @@ found:
break;
case Zlit:
- if(HEADTYPE == 8 && p->as == ARET) {
- // native client return.
- for(z=0; z<sizeof(naclret); z++)
- *andptr++ = naclret[z];
- break;
- }
for(; op = o->op[z]; z++)
*andptr++ = op;
break;
@@ -1040,137 +923,100 @@ found:
break;
case Zo_m:
- if(HEADTYPE == 8) {
- Adr a;
-
- switch(p->as) {
- case AJMP:
- if(p->to.type < D_AX || p->to.type > D_DI)
- diag("indirect jmp must use register in native client");
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&p->to, 04);
- *andptr++ = ~31;
- // JMP REG
- *andptr++ = 0xFF;
- asmand(&p->to, 04);
- return;
-
- case ACALL:
- a = p->to;
- // native client indirect call
- if(a.type < D_AX || a.type > D_DI) {
- // MOVL target into BX
- *andptr++ = 0x8b;
- asmand(&p->to, reg[D_BX]);
- memset(&a, 0, sizeof a);
- a.type = D_BX;
- }
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&a, 04);
- *andptr++ = ~31;
- // CALL REG
- *andptr++ = 0xFF;
- asmand(&a, 02);
- return;
- }
- }
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
- if(HEADTYPE == 8 && p->as == AINT && v == 3) {
- // native client disallows all INT instructions.
- // translate INT $3 to HLT.
- *andptr++ = 0xf4;
- break;
- }
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ v = vaddr(a, nil);
*andptr++ = op;
*andptr++ = v;
break;
case Zib_rp:
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zib_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmand(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmand(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmand(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmand(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1185,99 +1031,128 @@ found:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
break;
-
- case Zbr:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- p->bigjmp = 1;
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
+
case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
- }
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
- break;
-
- case Zcallcon:
- v = p->to.offset - p->pc - 5;
*andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->sym = q->from.sym;
+ put4(0);
break;
+ case Zbr:
case Zjmp:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ // jump out of function
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
+ }
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
+ }
+
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
+
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
- p->bigjmp = 1;
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+ case Zcallcon:
case Zjmpcon:
- v = p->to.offset - p->pc - 5;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(t[2] == Zcallcon)
+ *andptr++ = op;
+ else
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->add = p->to.offset;
+ put4(0);
break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ if(q == nil) {
+ diag("loop without target");
+ errorexit();
}
+ v = q->pc - p->pc - 2;
+ if(v < -128 && v > 127)
+ diag("loop too far: %P", p);
+ *andptr++ = op;
+ *andptr++ = v;
break;
case Zbyte:
+ v = vaddr(&p->from, &rel);
+ if(rel.siz != 0) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1342,7 +1217,7 @@ bad:
}
return;
}
- diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
+ diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
return;
mfound:
@@ -1441,204 +1316,10 @@ mfound:
void
asmins(Prog *p)
{
- if(HEADTYPE == 8) {
- ulong npc;
- static Prog *prefix;
-
- // native client
- // - pad indirect jump targets (aka ATEXT) to 32-byte boundary
- // - instructions cannot cross 32-byte boundary
- // - end of call (return address) must be on 32-byte boundary
- if(p->as == ATEXT)
- p->pc += 31 & -p->pc;
- if(p->as == ACALL) {
- // must end on 32-byte boundary.
- // doasm to find out how long the CALL encoding is.
- andptr = and;
- doasm(p);
- npc = p->pc + (andptr - and);
- p->pc += 31 & -npc;
- }
- if(p->as == AREP || p->as == AREPN) {
- // save prefix for next instruction,
- // so that inserted NOPs do not split (e.g.) REP / MOVSL sequence.
- prefix = p;
- andptr = and;
- return;
- }
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- npc = p->pc + (andptr - and);
- if(andptr > and && (p->pc&~31) != ((npc-1)&~31)) {
- // crossed 32-byte boundary; pad to boundary and try again
- p->pc += 31 & -p->pc;
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- }
- prefix = nil;
- } else {
- andptr = and;
- doasm(p);
- }
+ andptr = and;
+ doasm(p);
if(andptr > and+sizeof and) {
print("and[] is too short - %d byte instruction\n", andptr - and);
errorexit();
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
index 98b89f0a2..71f23383d 100644
--- a/src/cmd/cc/Makefile
+++ b/src/cmd/cc/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-LIB=\
- cc.a$O\
+LIB=cc.a
HFILES=\
cc.h\
@@ -30,18 +30,7 @@ OFILES=\
dpchk.$O\
omachcap.$O\
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
-
-$(OFILES): $(HFILES)
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O *.6 enam.c 6.out a.out y.tab.h y.tab.c $(LIB)
+NOINSTALL=1
+include ../../Make.clib
install: $(LIB)
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
index eb7968c4f..c6a6722bd 100644
--- a/src/cmd/cc/acid.c
+++ b/src/cmd/cc/acid.c
@@ -150,7 +150,7 @@ acidmember(Type *t, int32 off, int flag)
if(typesu[l->etype]) {
s1 = acidsue(l->link);
if(s1 != S) {
- Bprint(&outbuf, " 'A' %s %ld %s;\n",
+ Bprint(&outbuf, " 'A' %s %d %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
break;
@@ -189,7 +189,7 @@ acidmember(Type *t, int32 off, int flag)
if(s == S)
break;
if(flag) {
- Bprint(&outbuf, " '%c' %ld %s;\n",
+ Bprint(&outbuf, " '%c' %d %s;\n",
acidchar[t->etype], t->offset+off, amap(s->name));
} else {
Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
@@ -209,7 +209,7 @@ acidmember(Type *t, int32 off, int flag)
acidmember(l, t->offset+off, flag);
Bprint(&outbuf, " };\n");
} else {
- Bprint(&outbuf, " %s %ld %s;\n",
+ Bprint(&outbuf, " %s %d %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
}
@@ -223,7 +223,7 @@ acidmember(Type *t, int32 off, int flag)
} else {
Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
amap(s1->name));
- Bprint(&outbuf, "\tindent_%s(addr+%ld, indent+\"\\t\");\n",
+ Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
amap(s1->name), t->offset+off);
Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
}
@@ -263,7 +263,7 @@ acidtype(Type *t)
if(debug['s'])
goto asmstr;
an = amap(s->name);
- Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
+ Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width);
Bprint(&outbuf, "aggr %s\n{\n", an);
for(l = t->link; l != T; l = l->down)
acidmember(l, 0, 1);
@@ -280,7 +280,7 @@ acidtype(Type *t)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ Bprint(&outbuf, "#define\t%s.%s\t%d\n",
s->name,
l->sym->name,
l->offset);
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 69adcccb0..3649bf5f6 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -166,6 +166,7 @@ struct Type
uchar nbits;
uchar etype;
uchar garb;
+ uchar align;
};
#define T ((Type*)0)
@@ -785,7 +786,7 @@ int32 outlstring(ushort*, int32);
void sextern(Sym*, Node*, int32, int32);
void xcom(Node*);
int32 exreg(Type*);
-int32 align(int32, Type*, int);
+int32 align(int32, Type*, int, int32*);
int32 maxround(int32, int32);
extern schar ewidth[];
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
index 5cbe8b77c..b1a8a4704 100644
--- a/src/cmd/cc/com.c
+++ b/src/cmd/cc/com.c
@@ -638,10 +638,10 @@ tcomo(Node *n, int f)
n->addable = 1;
if(n->class == CEXREG) {
n->op = OREGISTER;
- // on 386, "extern register" generates
+ // on 386 or amd64, "extern register" generates
// memory references relative to the
- // fs segment.
- if(thechar == '8') // [sic]
+ // gs or fs segment.
+ if(thechar == '8' || thechar == '6') // [sic]
n->op = OEXREG;
n->reg = n->sym->offset;
n->xoffset = 0;
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index b4d8c4d14..f629925d1 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -195,7 +195,7 @@ doinit(Sym *s, Type *t, int32 o, Node *a)
dbgdecl(s);
}
if(debug['i']) {
- print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
prtree(a, "doinit value");
}
@@ -323,7 +323,7 @@ init1(Sym *s, Type *t, int32 o, int exflag)
return Z;
if(debug['i']) {
- print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
prtree(a, "init1 value");
}
@@ -479,7 +479,7 @@ init1(Sym *s, Type *t, int32 o, int exflag)
e = r->vconst;
if(t->width != 0)
if(e < 0 || e*w >= t->width) {
- diag(a, "initialization index out of range: %ld", e);
+ diag(a, "initialization index out of range: %d", e);
continue;
}
}
@@ -552,9 +552,10 @@ void
sualign(Type *t)
{
Type *l;
- int32 o, w;
+ int32 o, w, maxal;
o = 0;
+ maxal = 0;
switch(t->etype) {
case TSTRUCT:
@@ -577,13 +578,14 @@ sualign(Type *t)
l->sym->name);
else
diag(Z, "incomplete structure element");
- w = align(w, l, Ael1);
+ w = align(w, l, Ael1, &maxal);
l->offset = w;
- w = align(w, l, Ael2);
+ w = align(w, l, Ael2, &maxal);
}
}
- w = align(w, t, Asu2);
+ w = align(w, t, Asu2, &maxal);
t->width = w;
+ t->align = maxal;
acidtype(t);
pickletype(t);
return;
@@ -600,12 +602,13 @@ sualign(Type *t)
diag(Z, "incomplete union element");
l->offset = 0;
l->shift = 0;
- o = align(align(0, l, Ael1), l, Ael2);
+ o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
if(o > w)
w = o;
}
- w = align(w, t, Asu2);
+ w = align(w, t, Asu2, &maxal);
t->width = w;
+ t->align = maxal;
acidtype(t);
pickletype(t);
return;
@@ -663,7 +666,7 @@ argmark(Node *n, int pass)
{
Type *t;
- autoffset = align(0, thisfn->link, Aarg0);
+ autoffset = align(0, thisfn->link, Aarg0, nil);
stkoff = 0;
for(; n->left != Z; n = n->left) {
if(n->op != OFUNC || n->left->op != ONAME)
@@ -745,9 +748,9 @@ loop:
firstarg = s;
firstargtype = s->type;
}
- autoffset = align(autoffset, s->type, Aarg1);
+ autoffset = align(autoffset, s->type, Aarg1, nil);
s->offset = autoffset;
- autoffset = align(autoffset, s->type, Aarg2);
+ autoffset = align(autoffset, s->type, Aarg2, nil);
} else
dodecl(pdecl, CXXX, types[TINT], n);
break;
@@ -916,7 +919,7 @@ fnproto1(Node *n)
void
dbgdecl(Sym *s)
{
- print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+ print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
s->name, cnames[s->class], s->block, s->offset, s->type);
}
@@ -1275,7 +1278,7 @@ adecl(int c, Type *t, Sym *s)
}
switch(c) {
case CAUTO:
- autoffset = align(autoffset, t, Aaut3);
+ autoffset = align(autoffset, t, Aaut3, nil);
stkoff = maxround(stkoff, autoffset);
s->offset = -autoffset;
break;
@@ -1285,10 +1288,10 @@ adecl(int c, Type *t, Sym *s)
firstarg = s;
firstargtype = t;
}
- autoffset = align(autoffset, t, Aarg1);
+ autoffset = align(autoffset, t, Aarg1, nil);
if(s)
s->offset = autoffset;
- autoffset = align(autoffset, t, Aarg2);
+ autoffset = align(autoffset, t, Aarg2, nil);
break;
}
}
@@ -1571,7 +1574,7 @@ contig(Sym *s, Node *n, int32 v)
Type *zt;
if(debug['i']) {
- print("contig v = %ld; s = %s\n", v, s->name);
+ print("contig v = %d; s = %s\n", v, s->name);
prtree(n, "doinit value");
}
@@ -1587,7 +1590,7 @@ contig(Sym *s, Node *n, int32 v)
if(v != 0)
diag(n, "automatic adjustable array: %s", s->name);
v = s->offset;
- autoffset = align(autoffset, s->type, Aaut3);
+ autoffset = align(autoffset, s->type, Aaut3, nil);
s->offset = -autoffset;
stkoff = maxround(stkoff, autoffset);
symadjust(s, n, v - s->offset);
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 046c0e4da..6eb5fb409 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -369,7 +369,7 @@ checkargs(Node *nn, char *s, int pos)
continue;
for(l=tprot; l; l=l->link)
if(sametype(a->type, l->type)) {
-/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
if(beq(flag, l->flag))
goto loop;
}
@@ -400,6 +400,7 @@ dpcheck(Node *n)
i = l->param;
b = n->right;
+ a = Z;
while(i > 0) {
b = nextarg(b, &a);
i--;
@@ -437,9 +438,9 @@ pragpack(void)
;
if(debug['f'])
if(packflg)
- print("%4ld: pack %d\n", lineno, packflg);
+ print("%4d: pack %d\n", lineno, packflg);
else
- print("%4ld: pack off\n", lineno);
+ print("%4d: pack off\n", lineno);
}
void
@@ -459,9 +460,9 @@ pragfpround(void)
;
if(debug['f'])
if(fproundflg)
- print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ print("%4d: fproundflg %d\n", lineno, fproundflg);
else
- print("%4ld: fproundflg off\n", lineno);
+ print("%4d: fproundflg off\n", lineno);
}
void
@@ -477,7 +478,7 @@ pragtextflag(void)
while(getnsc() != '\n')
;
if(debug['f'])
- print("%4ld: textflag %d\n", lineno, textflag);
+ print("%4d: textflag %d\n", lineno, textflag);
}
void
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index c9facc667..3b413c246 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -38,7 +38,7 @@
int
systemtype(int sys)
{
-#ifdef __MINGW32__
+#ifdef _WIN32
return sys&Windows;
#else
return sys&Plan9;
@@ -630,7 +630,7 @@ l1:
vv = c;
yylval.vval = convvtox(vv, TUCHAR);
if(yylval.vval != vv)
- yyerror("overflow in character constant: 0x%lx", c);
+ yyerror("overflow in character constant: 0x%x", c);
else
if(c & 0x80){
nearln = lineno;
@@ -1410,11 +1410,11 @@ Lconv(Fmt *fp)
strcat(str, " ");
}
if(a[i].line)
- snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ snprint(s, STRINGSZ, "%s:%d[%s:%d]",
a[i].line->name, l-a[i].ldel+1,
a[i].incl->name, l-a[i].idel+1);
else
- snprint(s, STRINGSZ, "%s:%ld",
+ snprint(s, STRINGSZ, "%s:%d",
a[i].incl->name, l-a[i].idel+1);
if(strlen(s)+strlen(str) >= STRINGSZ-10)
break;
@@ -1463,7 +1463,7 @@ Tconv(Fmt *fp)
n = t->width;
if(t->link && t->link->width)
n /= t->link->width;
- sprint(s, "[%ld]", n);
+ sprint(s, "[%d]", n);
if(strlen(str) + strlen(s) < STRINGSZ)
strcat(str, s);
}
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index ca8a54c0b..35740e985 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -63,7 +63,7 @@ getsym(void)
if(cp <= symb+NSYMB-4)
*cp++ = c;
c = getc();
- if(isalnum(c) || c == '_' || c >= 0x80)
+ if(isalnum(c) || c == '_' || c >= 0x80 || c == '$')
continue;
unget(c);
break;
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index cd6fffc57..a9d7f1ef4 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -37,7 +37,7 @@ argsize(void)
int32 s;
//print("t=%T\n", thisfn);
- s = align(0, thisfn->link, Aarg0);
+ s = align(0, thisfn->link, Aarg0, nil);
for(t=thisfn->down; t!=T; t=t->down) {
switch(t->etype) {
case TVOID:
@@ -47,8 +47,8 @@ argsize(void)
s += 64;
break;
default:
- s = align(s, t, Aarg1);
- s = align(s, t, Aarg2);
+ s = align(s, t, Aarg1, nil);
+ s = align(s, t, Aarg2, nil);
break;
}
//print(" %d %T\n", s, t);
@@ -99,7 +99,7 @@ codgen(Node *n, Node *nn)
nod1 = *nodret->left;
nod1.sym = firstarg;
nod1.type = firstargtype;
- nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.xoffset = align(0, firstargtype, Aarg1, nil);
nod1.etype = firstargtype->etype;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c
index fb7ec585b..82cf5eb05 100644
--- a/src/cmd/cc/pickle.c
+++ b/src/cmd/cc/pickle.c
@@ -143,7 +143,7 @@ picklemember(Type *t, int32 off)
case TIND:
if(s == S)
Bprint(&outbuf,
- "%s\"p\", (char*)addr+%ld+_i*%ld);\n",
+ "%s\"p\", (char*)addr+%d+_i*%d);\n",
picklestr, t->offset+off, t->width);
else
Bprint(&outbuf,
@@ -164,14 +164,14 @@ picklemember(Type *t, int32 off)
case TFLOAT:
case TDOUBLE:
if(s == S)
- Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
+ 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 < %ld; _i++) {\n\t",
+ 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");
@@ -183,7 +183,7 @@ picklemember(Type *t, int32 off)
if(s1 == S)
break;
if(s == S) {
- Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
+ 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",
@@ -235,7 +235,7 @@ pickletype(Type *t)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ Bprint(&outbuf, "#define\t%s.%s\t%d\n",
s->name,
l->sym->name,
l->offset);
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
index 02d4e64a0..0e402dea7 100644
--- a/src/cmd/cc/pswt.c
+++ b/src/cmd/cc/pswt.c
@@ -80,7 +80,7 @@ doswit(Node *n)
qsort(iq, nc, sizeof(C1), swcmp);
if(debug['W'])
for(i=0; i<nc; i++)
- print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+ print("case %2d: = %.8llux\n", i, (vlong)iq[i].val);
for(i=0; i<nc-1; i++)
if(iq[i].val == iq[i+1].val)
diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
@@ -115,7 +115,7 @@ outlstring(ushort *s, int32 n)
r = nstring;
while(n > 0) {
c = *s++;
- if(align(0, types[TCHAR], Aarg1)) {
+ if(align(0, types[TCHAR], Aarg1, nil)) {
buf[0] = c>>8;
buf[1] = c;
} else {
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
index 335d30bfb..e0d5df719 100644
--- a/src/cmd/cc/sub.c
+++ b/src/cmd/cc/sub.c
@@ -92,18 +92,18 @@ prtree1(Node *n, int d, int f)
{
case ONAME:
print(" \"%F\"", n);
- print(" %ld", n->xoffset);
+ print(" %d", n->xoffset);
i = 0;
break;
case OINDREG:
- print(" %ld(R%d)", n->xoffset, n->reg);
+ print(" %d(R%d)", n->xoffset, n->reg);
i = 0;
break;
case OREGISTER:
if(n->xoffset)
- print(" %ld+R%d", n->xoffset, n->reg);
+ print(" %d+R%d", n->xoffset, n->reg);
else
print(" R%d", n->reg);
i = 0;
@@ -845,7 +845,7 @@ simplifyshift(Node *n)
/*
if(debug['h'])
- print("%.3o %ld %ld %d #%.lux\n",
+ print("%.3o %d %d %d #%.ux\n",
(s1<<3)|s2, c1, c2, topbit(c3), c3);
*/
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
index 34ca3dd46..5458c3e4f 100644
--- a/src/cmd/cgo/Makefile
+++ b/src/cmd/cgo/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=cgo
GOFILES=\
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 580a72a95..8689ac3da 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -12,63 +12,13 @@ import (
"go/doc"
"go/parser"
"go/scanner"
+ "go/token"
"os"
"strings"
)
-// A Cref refers to an expression of the form C.xxx in the AST.
-type Cref struct {
- Name string
- Expr *ast.Expr
- Context string // "type", "expr", "const", or "call"
- TypeName bool // whether xxx is a C type name
- Type *Type // the type of xxx
- FuncType *FuncType
-}
-
-// A ExpFunc is an exported function, callable from C.
-type ExpFunc struct {
- Func *ast.FuncDecl
- ExpName string // name to use from C
-}
-
-// A Prog collects information about a cgo program.
-type Prog struct {
- AST *ast.File // parsed AST
- Preamble string // C preamble (doc comment on import "C")
- PackagePath string
- Package string
- Crefs []*Cref
- Typedef map[string]ast.Expr
- Vardef map[string]*Type
- Funcdef map[string]*FuncType
- Enumdef map[string]int64
- Constdef map[string]string
- ExpFuncs []*ExpFunc
- PtrSize int64
- GccOptions []string
- OutDefs map[string]bool
-}
-
-// A Type collects information about a type in both the C and Go worlds.
-type Type struct {
- Size int64
- Align int64
- C string
- Go ast.Expr
- EnumValues map[string]int64
-}
-
-// A FuncType collects information about a function type in both the C and Go worlds.
-type FuncType struct {
- Params []*Type
- Result *Type
- Go *ast.FuncType
-}
-
-func openProg(name string, p *Prog) {
- var err os.Error
- p.AST, err = parser.ParseFile(name, nil, nil, parser.ParseComments)
+func parse(name string, flags uint) *ast.File {
+ ast1, err := parser.ParseFile(fset, name, nil, flags)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just
@@ -82,25 +32,37 @@ func openProg(name string, p *Prog) {
}
fatal("parsing %s: %s", name, err)
}
- p.Package = p.AST.Name.Name()
+ return ast1
+}
- // Find the import "C" line and get any extra C preamble.
- // Delete the import "C" line along the way.
+// 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,
+// a list of exported functions, and the actual AST, to be rewritten and
+// printed.
+func (f *File) ReadGo(name string) {
+ // Two different parses: once with comments, once without.
+ // The printer is not good enough at printing comments in the
+ // right place when we start editing the AST behind its back,
+ // so we use ast1 to look for the doc comments on import "C"
+ // and on exported functions, and we use ast2 for translating
+ // and reprinting.
+ ast1 := parse(name, parser.ParseComments)
+ ast2 := parse(name, 0)
+
+ f.Package = ast1.Name.Name
+ f.Name = make(map[string]*Name)
+
+ // In ast1, find the import "C" line and get any extra C preamble.
sawC := false
- w := 0
- for _, decl := range p.AST.Decls {
+ for _, decl := range ast1.Decls {
d, ok := decl.(*ast.GenDecl)
if !ok {
- p.AST.Decls[w] = decl
- w++
continue
}
- ws := 0
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
if !ok || string(s.Path.Value) != `"C"` {
- d.Specs[ws] = spec
- ws++
continue
}
sawC = true
@@ -108,269 +70,330 @@ func openProg(name string, p *Prog) {
error(s.Path.Pos(), `cannot rename import "C"`)
}
if s.Doc != nil {
- p.Preamble += doc.CommentText(s.Doc) + "\n"
+ f.Preamble += doc.CommentText(s.Doc) + "\n"
} else if len(d.Specs) == 1 && d.Doc != nil {
- p.Preamble += doc.CommentText(d.Doc) + "\n"
+ f.Preamble += doc.CommentText(d.Doc) + "\n"
+ }
+ }
+ }
+ if !sawC {
+ error(token.NoPos, `cannot find import "C"`)
+ }
+
+ // In ast2, strip the import "C" line.
+ w := 0
+ for _, decl := range ast2.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ ast2.Decls[w] = decl
+ w++
+ continue
+ }
+ ws := 0
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec)
+ if !ok || string(s.Path.Value) != `"C"` {
+ d.Specs[ws] = spec
+ ws++
}
}
if ws == 0 {
continue
}
d.Specs = d.Specs[0:ws]
- p.AST.Decls[w] = d
+ ast2.Decls[w] = d
w++
}
- p.AST.Decls = p.AST.Decls[0:w]
-
- if !sawC {
- error(noPos, `cannot find import "C"`)
- }
+ ast2.Decls = ast2.Decls[0:w]
// Accumulate pointers to uses of C.x.
- if p.Crefs == nil {
- p.Crefs = make([]*Cref, 0, 8)
+ if f.Ref == nil {
+ f.Ref = make([]*Ref, 0, 8)
}
- walk(p.AST, p, "prog")
+ f.walk(ast2, "prog", (*File).saveRef)
+
+ // Accumulate exported functions.
+ // The comments are only on ast1 but we need to
+ // save the function bodies from ast2.
+ // The first walk fills in ExpFunc, and the
+ // second walk changes the entries to
+ // refer to ast2 instead.
+ f.walk(ast1, "prog", (*File).saveExport)
+ f.walk(ast2, "prog", (*File).saveExport2)
+
+ f.AST = ast2
}
-func walk(x interface{}, p *Prog, context string) {
- switch n := x.(type) {
- case *ast.Expr:
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Name() == "C" {
- i := len(p.Crefs)
- if i >= cap(p.Crefs) {
- new := make([]*Cref, 2*i)
- for j, v := range p.Crefs {
- new[j] = v
- }
- p.Crefs = new
- }
- p.Crefs = p.Crefs[0 : i+1]
- p.Crefs[i] = &Cref{
- Name: sel.Sel.Name(),
- Expr: n,
- Context: context,
+// Save references to C.xxx for later processing.
+func (f *File) saveRef(x interface{}, context string) {
+ n, ok := x.(*ast.Expr)
+ if !ok {
+ return
+ }
+ if sel, ok := (*n).(*ast.SelectorExpr); ok {
+ // For now, assume that the only instance of capital C is
+ // when used as the imported package identifier.
+ // The parser should take care of scoping in the future,
+ // so that we will be able to distinguish a "top-level C"
+ // from a local C.
+ if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
+ if context == "as2" {
+ context = "expr"
+ }
+ goname := sel.Sel.Name
+ if goname == "errno" {
+ error(sel.Pos(), "cannot refer to errno directly; see documentation")
+ return
+ }
+ name := f.Name[goname]
+ if name == nil {
+ name = &Name{
+ Go: goname,
}
- break
+ f.Name[goname] = name
}
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+ return
}
- walk(*n, p, context)
+ }
+}
+
+// If a function should be exported add it to ExpFunc.
+func (f *File) saveExport(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ if n.Doc == nil {
+ return
+ }
+ for _, c := range n.Doc.List {
+ if string(c.Text[0:9]) != "//export " {
+ continue
+ }
+
+ name := strings.TrimSpace(string(c.Text[9:]))
+ if name == "" {
+ error(c.Pos(), "export missing name")
+ }
+
+ f.ExpFunc = append(f.ExpFunc, &ExpFunc{
+ Func: n,
+ ExpName: name,
+ })
+ break
+ }
+}
+
+// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
+func (f *File) saveExport2(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ for _, exp := range f.ExpFunc {
+ if exp.Func.Name.Name == n.Name.Name {
+ exp.Func = n
+ break
+ }
+ }
+}
+
+// walk walks the AST x, calling visit(f, x, context) for each node.
+func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
+ visit(f, x, context)
+ switch n := x.(type) {
+ case *ast.Expr:
+ f.walk(*n, context, visit)
// everything else just recurs
default:
- error(noPos, "unexpected type %T in walk", x)
+ error(token.NoPos, "unexpected type %T in walk", x, visit)
panic("unexpected type")
case nil:
// These are ordered and grouped to match ../../pkg/go/ast/ast.go
case *ast.Field:
- walk(&n.Type, p, "type")
+ f.walk(&n.Type, "type", visit)
case *ast.FieldList:
- for _, f := range n.List {
- walk(f, p, context)
+ for _, field := range n.List {
+ f.walk(field, context, visit)
}
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
case *ast.BasicLit:
case *ast.FuncLit:
- walk(n.Type, p, "type")
- walk(n.Body, p, "stmt")
+ f.walk(n.Type, "type", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.CompositeLit:
- walk(&n.Type, p, "type")
- walk(n.Elts, p, "expr")
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Elts, "expr", visit)
case *ast.ParenExpr:
- walk(&n.X, p, context)
+ f.walk(&n.X, context, visit)
case *ast.SelectorExpr:
- walk(&n.X, p, "selector")
+ f.walk(&n.X, "selector", visit)
case *ast.IndexExpr:
- walk(&n.X, p, "expr")
- walk(&n.Index, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Index, "expr", visit)
case *ast.SliceExpr:
- walk(&n.X, p, "expr")
- walk(&n.Index, p, "expr")
- if n.End != nil {
- walk(&n.End, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ if n.Low != nil {
+ f.walk(&n.Low, "expr", visit)
+ }
+ if n.High != nil {
+ f.walk(&n.High, "expr", visit)
}
case *ast.TypeAssertExpr:
- walk(&n.X, p, "expr")
- walk(&n.Type, p, "type")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Type, "type", visit)
case *ast.CallExpr:
- walk(&n.Fun, p, "call")
- walk(n.Args, p, "expr")
+ if context == "as2" {
+ f.walk(&n.Fun, "call2", visit)
+ } else {
+ f.walk(&n.Fun, "call", visit)
+ }
+ f.walk(n.Args, "expr", visit)
case *ast.StarExpr:
- walk(&n.X, p, context)
+ f.walk(&n.X, context, visit)
case *ast.UnaryExpr:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.BinaryExpr:
- walk(&n.X, p, "expr")
- walk(&n.Y, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Y, "expr", visit)
case *ast.KeyValueExpr:
- walk(&n.Key, p, "expr")
- walk(&n.Value, p, "expr")
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
case *ast.ArrayType:
- walk(&n.Len, p, "expr")
- walk(&n.Elt, p, "type")
+ f.walk(&n.Len, "expr", visit)
+ f.walk(&n.Elt, "type", visit)
case *ast.StructType:
- walk(n.Fields, p, "field")
+ f.walk(n.Fields, "field", visit)
case *ast.FuncType:
- walk(n.Params, p, "field")
+ f.walk(n.Params, "field", visit)
if n.Results != nil {
- walk(n.Results, p, "field")
+ f.walk(n.Results, "field", visit)
}
case *ast.InterfaceType:
- walk(n.Methods, p, "field")
+ f.walk(n.Methods, "field", visit)
case *ast.MapType:
- walk(&n.Key, p, "type")
- walk(&n.Value, p, "type")
+ f.walk(&n.Key, "type", visit)
+ f.walk(&n.Value, "type", visit)
case *ast.ChanType:
- walk(&n.Value, p, "type")
+ f.walk(&n.Value, "type", visit)
case *ast.BadStmt:
case *ast.DeclStmt:
- walk(n.Decl, p, "decl")
+ f.walk(n.Decl, "decl", visit)
case *ast.EmptyStmt:
case *ast.LabeledStmt:
- walk(n.Stmt, p, "stmt")
+ f.walk(n.Stmt, "stmt", visit)
case *ast.ExprStmt:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.IncDecStmt:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.AssignStmt:
- walk(n.Lhs, p, "expr")
- walk(n.Rhs, p, "expr")
+ f.walk(n.Lhs, "expr", visit)
+ if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
+ f.walk(n.Rhs, "as2", visit)
+ } else {
+ f.walk(n.Rhs, "expr", visit)
+ }
case *ast.GoStmt:
- walk(n.Call, p, "expr")
+ f.walk(n.Call, "expr", visit)
case *ast.DeferStmt:
- walk(n.Call, p, "expr")
+ f.walk(n.Call, "expr", visit)
case *ast.ReturnStmt:
- walk(n.Results, p, "expr")
+ f.walk(n.Results, "expr", visit)
case *ast.BranchStmt:
case *ast.BlockStmt:
- walk(n.List, p, "stmt")
+ f.walk(n.List, "stmt", visit)
case *ast.IfStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Cond, p, "expr")
- walk(n.Body, p, "stmt")
- walk(n.Else, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
+ f.walk(n.Else, "stmt", visit)
case *ast.CaseClause:
- walk(n.Values, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Values, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.SwitchStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Tag, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Tag, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.TypeCaseClause:
- walk(n.Types, p, "type")
- walk(n.Body, p, "stmt")
+ f.walk(n.Types, "type", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.TypeSwitchStmt:
- walk(n.Init, p, "stmt")
- walk(n.Assign, p, "stmt")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(n.Assign, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.CommClause:
- walk(n.Lhs, p, "expr")
- walk(n.Rhs, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Lhs, "expr", visit)
+ f.walk(n.Rhs, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.SelectStmt:
- walk(n.Body, p, "stmt")
+ f.walk(n.Body, "stmt", visit)
case *ast.ForStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Cond, p, "expr")
- walk(n.Post, p, "stmt")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Post, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.RangeStmt:
- walk(&n.Key, p, "expr")
- walk(&n.Value, p, "expr")
- walk(&n.X, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+ f.walk(&n.X, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.ImportSpec:
case *ast.ValueSpec:
- walk(&n.Type, p, "type")
- walk(n.Values, p, "expr")
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Values, "expr", visit)
case *ast.TypeSpec:
- walk(&n.Type, p, "type")
+ f.walk(&n.Type, "type", visit)
case *ast.BadDecl:
case *ast.GenDecl:
- walk(n.Specs, p, "spec")
+ f.walk(n.Specs, "spec", visit)
case *ast.FuncDecl:
if n.Recv != nil {
- walk(n.Recv, p, "field")
+ f.walk(n.Recv, "field", visit)
}
- walk(n.Type, p, "type")
+ f.walk(n.Type, "type", visit)
if n.Body != nil {
- walk(n.Body, p, "stmt")
+ f.walk(n.Body, "stmt", visit)
}
- checkExpFunc(n, p)
-
case *ast.File:
- walk(n.Decls, p, "decl")
+ f.walk(n.Decls, "decl", visit)
case *ast.Package:
- for _, f := range n.Files {
- walk(f, p, "file")
+ for _, file := range n.Files {
+ f.walk(file, "file", visit)
}
case []ast.Decl:
for _, d := range n {
- walk(d, p, context)
+ f.walk(d, context, visit)
}
case []ast.Expr:
for i := range n {
- walk(&n[i], p, context)
+ f.walk(&n[i], context, visit)
}
case []ast.Stmt:
for _, s := range n {
- walk(s, p, context)
+ f.walk(s, context, visit)
}
case []ast.Spec:
for _, s := range n {
- walk(s, p, context)
- }
- }
-}
-
-// If a function should be exported add it to ExpFuncs.
-func checkExpFunc(n *ast.FuncDecl, p *Prog) {
- if n.Doc == nil {
- return
- }
- for _, c := range n.Doc.List {
- if string(c.Text[0:9]) != "//export " {
- continue
- }
-
- name := strings.TrimSpace(string(c.Text[9:]))
- if name == "" {
- error(c.Position, "export missing name")
- }
-
- if p.ExpFuncs == nil {
- p.ExpFuncs = make([]*ExpFunc, 0, 8)
+ f.walk(s, context, visit)
}
- i := len(p.ExpFuncs)
- if i >= cap(p.ExpFuncs) {
- new := make([]*ExpFunc, 2*i)
- for j, v := range p.ExpFuncs {
- new[j] = v
- }
- p.ExpFuncs = new
- }
- p.ExpFuncs = p.ExpFuncs[0 : i+1]
- p.ExpFuncs[i] = &ExpFunc{
- Func: n,
- ExpName: name,
- }
- break
}
}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 022a87c15..0f9204d7f 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -23,6 +23,31 @@ the package. For example:
// #include <errno.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.
+
+The standard C numeric types are available under the names
+C.char, C.schar (signed char), C.uchar (unsigned char),
+C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
+C.long, C.ulong (unsigned long), C.longlong (long long),
+C.ulonglong (unsigned long long), C.float, C.double.
+
+To access a struct, union, or enum type directly, prefix it with
+struct_, union_, or enum_, as in C.struct_stat.
+
+Any C function that returns a value may be called in a multiple
+assignment context to retrieve both the return value and the
+C errno variable as an os.Error. For example:
+
+ n, err := C.atoi("abc")
+
+In C, a function argument written as a fixed size array
+actually requires a pointer to the first element of the array.
+C compilers are aware of this calling convention and adjust
+the call accordingly, but Go cannot. In Go, you must pass
+the pointer to the first element explicitly: C.f(&x[0]).
+
Cgo transforms the input file into four output files: two Go source
files, a C file for 6c (or 8c or 5c), and a C file for gcc.
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 5e12a6687..be3b8fe64 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Annotate Crefs in Prog with C types by parsing gcc debug output.
+// Annotate Ref in Prog with C types by parsing gcc debug output.
// Conversion of debug output to Go types.
package main
@@ -12,6 +12,8 @@ import (
"debug/dwarf"
"debug/elf"
"debug/macho"
+ "debug/pe"
+ "flag"
"fmt"
"go/ast"
"go/parser"
@@ -21,12 +23,64 @@ import (
"strings"
)
-func (p *Prog) loadDebugInfo() {
+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",
+}
+
+// cname returns the C name to use for C.s.
+// The expansions are listed in nameToC and also
+// struct_foo becomes "struct foo", and similarly for
+// union and enum.
+func cname(s string) string {
+ if t, ok := nameToC[s]; ok {
+ return t
+ }
+
+ if strings.HasPrefix(s, "struct_") {
+ return "struct " + s[len("struct_"):]
+ }
+ if strings.HasPrefix(s, "union_") {
+ return "union " + s[len("union_"):]
+ }
+ if strings.HasPrefix(s, "enum_") {
+ return "enum " + s[len("enum_"):]
+ }
+ return s
+}
+
+// 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.
+func (p *Package) Translate(f *File) {
+ for _, cref := range f.Ref {
+ // Convert C.ulong to C.unsigned long, etc.
+ cref.Name.C = cname(cref.Name.Go)
+ }
+ p.loadDefines(f)
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, needType)
+ }
+ p.rewriteRef(f)
+}
+
+// loadDefines coerces gcc into spitting out the #defines in use
+// in the file f and saves relevant renamings in f.Name[name].Define.
+func (p *Package) loadDefines(f *File) {
var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
+ stdout := p.gccDefines(b.Bytes())
- b.WriteString(p.Preamble)
- stdout := p.gccPostProc(b.Bytes())
- defines := make(map[string]string)
for _, line := range strings.Split(stdout, "\n", -1) {
if len(line) < 9 || line[0:7] != "#define" {
continue
@@ -48,70 +102,112 @@ func (p *Prog) loadDebugInfo() {
val = strings.TrimSpace(line[tabIndex:])
}
- // Only allow string, character, and numeric constants. Ignoring #defines for
- // symbols allows those symbols to be referenced in Go, as they will be
- // translated by gcc later.
- _, err := strconv.Atoi(string(val[0]))
- if err == nil || val[0] == '\'' || val[0] == '"' {
- defines[key] = val
- }
- }
-
- // Construct a slice of unique names from p.Crefs.
- m := make(map[string]int)
- for _, c := range p.Crefs {
- // If we've already found this name as a define, it is not a Cref.
- if val, ok := defines[c.Name]; ok {
- _, err := parser.ParseExpr("", val, nil)
- if err != nil {
- fmt.Fprintf(os.Stderr, "The value in C.%s does not parse as a Go expression; cannot use.\n", c.Name)
- os.Exit(2)
+ if n := f.Name[key]; n != nil {
+ if *debugDefine {
+ fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
}
-
- c.Context = "const"
- c.TypeName = false
- p.Constdef[c.Name] = val
- continue
+ n.Define = val
}
- m[c.Name] = -1
- }
- names := make([]string, 0, len(m))
- for name, _ := range m {
- i := len(names)
- names = names[0 : i+1]
- names[i] = name
- m[name] = i
}
+}
+// guessKinds tricks gcc into revealing the kind of each
+// name xxx for the references C.xxx in the Go input.
+// The kind is either a constant, type, or variable.
+func (p *Package) guessKinds(f *File) []*Name {
// Coerce gcc into telling us whether each name is
// a type, a value, or undeclared. We compile a function
// containing the line:
// name;
// If name is a type, gcc will print:
- // x.c:2: warning: useless type name in empty declaration
+ // cgo-test:2: warning: useless type name in empty declaration
// If name is a value, gcc will print
- // x.c:2: warning: statement with no effect
+ // cgo-test:2: warning: statement with no effect
// If name is undeclared, gcc will print
- // x.c:2: error: 'name' undeclared (first use in this function)
+ // cgo-test:2: error: 'name' undeclared (first use in this function)
// A line number directive causes the line number to
// correspond to the index in the names array.
- b.Reset()
- b.WriteString(p.Preamble)
+ //
+ // The line also has an enum declaration:
+ // name; enum { _cgo_enum_1 = name };
+ // If name is not a constant, gcc will print:
+ // cgo-test:4: error: enumerator value for '_cgo_enum_4' is not an integer constant
+ // we assume lines without that error are constants.
+
+ // Make list of names that need sniffing, type lookup.
+ toSniff := make([]*Name, 0, len(f.Name))
+ needType := make([]*Name, 0, len(f.Name))
+
+ for _, n := range f.Name {
+ // If we've already found this name as a #define
+ // and we can translate it as a constant value, do so.
+ if n.Define != "" {
+ ok := false
+ if _, err := strconv.Atoi(n.Define); err == nil {
+ ok = true
+ } else if n.Define[0] == '"' || n.Define[0] == '\'' {
+ _, err := parser.ParseExpr(fset, "", n.Define)
+ if err == nil {
+ ok = true
+ }
+ }
+ if ok {
+ n.Kind = "const"
+ n.Const = n.Define
+ continue
+ }
+
+ if isName(n.Define) {
+ n.C = n.Define
+ }
+ }
+
+ // If this is a struct, union, or enum type name,
+ // record the kind but also that we need type information.
+ if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
+ n.Kind = "type"
+ i := len(needType)
+ needType = needType[0 : i+1]
+ needType[i] = n
+ continue
+ }
+
+ i := len(toSniff)
+ toSniff = toSniff[0 : i+1]
+ toSniff[i] = n
+ }
+
+ if len(toSniff) == 0 {
+ return needType
+ }
+
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
b.WriteString("void f(void) {\n")
b.WriteString("#line 0 \"cgo-test\"\n")
- for _, n := range names {
- b.WriteString(n)
- b.WriteString(";\n")
+ for i, n := range toSniff {
+ fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
}
b.WriteString("}\n")
-
- kind := make(map[string]string)
- _, stderr := p.gccDebug(b.Bytes())
+ stderr := p.gccErrors(b.Bytes())
if stderr == "" {
- fatal("gcc produced no output")
+ fatal("gcc produced no output\non input:\n%s", b.Bytes())
}
+
+ names := make([]*Name, len(toSniff))
+ copy(names, toSniff)
+
+ isConst := make([]bool, len(toSniff))
+ for i := range isConst {
+ isConst[i] = true // until proven otherwise
+ }
+
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())
+ }
continue
}
line = line[9:]
@@ -127,28 +223,52 @@ func (p *Prog) loadDebugInfo() {
switch {
default:
continue
- case strings.Index(line, ": useless type name in empty declaration") >= 0:
+ case strings.Contains(line, ": useless type name in empty declaration"):
what = "type"
- case strings.Index(line, ": statement with no effect") >= 0:
- what = "value"
- case strings.Index(line, "undeclared") >= 0:
- what = "error"
+ isConst[i] = false
+ case strings.Contains(line, ": statement with no effect"):
+ what = "not-type" // const or func or var
+ case strings.Contains(line, "undeclared"):
+ error(token.NoPos, "%s", strings.TrimSpace(line[colon+1:]))
+ case strings.Contains(line, "is not an integer constant"):
+ isConst[i] = false
+ continue
}
- if old, ok := kind[names[i]]; ok && old != what {
- error(noPos, "inconsistent gcc output about C.%s", names[i])
+ n := toSniff[i]
+ if n == nil {
+ continue
}
- kind[names[i]] = what
+ toSniff[i] = nil
+ n.Kind = what
+
+ j := len(needType)
+ needType = needType[0 : j+1]
+ needType[j] = n
}
- for _, n := range names {
- if _, ok := kind[n]; !ok {
- error(noPos, "could not determine kind of name for C.%s", n)
+ for i, b := range isConst {
+ if b {
+ names[i].Kind = "const"
}
}
-
+ for _, n := range toSniff {
+ if n == nil {
+ continue
+ }
+ if n.Kind != "" {
+ continue
+ }
+ error(token.NoPos, "could not determine kind of name for C.%s", n.Go)
+ }
if nerrors > 0 {
- fatal("failed to interpret gcc output:\n%s", stderr)
+ fatal("unresolved names")
}
+ return needType
+}
+// loadDWARF parses the DWARF debug information generated
+// by gcc to learn the details of the constants, variables, and types
+// being referred to as C.xxx.
+func (p *Package) loadDWARF(f *File, names []*Name) {
// Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
@@ -157,19 +277,24 @@ func (p *Prog) loadDebugInfo() {
// typeof(names[i]) *__cgo__i;
// for each entry in names and then dereference the type we
// learn for __cgo__i.
- b.Reset()
- b.WriteString(p.Preamble)
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
for i, n := range names {
- fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n, i)
- }
- d, stderr := p.gccDebug(b.Bytes())
- if d == nil {
- fatal("gcc failed:\n%s\non input:\n%s", stderr, b.Bytes())
+ fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i)
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
+ }
}
+ d := p.gccDebug(b.Bytes())
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
enums := make([]dwarf.Offset, len(names))
+ nameToIndex := make(map[*Name]int)
+ for i, n := range names {
+ nameToIndex[n] = i
+ }
r := d.Reader()
for {
e, err := r.Next()
@@ -192,9 +317,11 @@ func (p *Prog) loadDebugInfo() {
}
if e.Tag == dwarf.TagEnumerator {
entryName := e.Val(dwarf.AttrName).(string)
- i, ok := m[entryName]
- if ok {
- enums[i] = offset
+ if strings.HasPrefix(entryName, "__cgo_enum__") {
+ n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
+ if 0 <= n && n < len(names) {
+ enums[n] = offset
+ }
}
}
}
@@ -234,97 +361,221 @@ func (p *Prog) loadDebugInfo() {
}
}
- // Record types and typedef information in Crefs.
+ // Record types and typedef information.
var conv typeConv
conv.Init(p.PtrSize)
- for _, c := range p.Crefs {
- i, ok := m[c.Name]
- if !ok {
- if _, ok := p.Constdef[c.Name]; !ok {
- fatal("Cref %s is no longer around", c.Name)
- }
- continue
- }
- c.TypeName = kind[c.Name] == "type"
+ for i, n := range names {
f, fok := types[i].(*dwarf.FuncType)
- if c.Context == "call" && !c.TypeName && fok {
- c.FuncType = conv.FuncType(f)
+ if n.Kind != "type" && fok {
+ n.Kind = "func"
+ n.FuncType = conv.FuncType(f)
} else {
- c.Type = conv.Type(types[i])
+ n.Type = conv.Type(types[i])
+ if enums[i] != 0 && n.Type.EnumValues != nil {
+ k := fmt.Sprintf("__cgo_enum__%d", i)
+ n.Kind = "const"
+ n.Const = strconv.Itoa64(n.Type.EnumValues[k])
+ // Remove injected enum to ensure the value will deep-compare
+ // equally in future loads of the same constant.
+ n.Type.EnumValues[k] = 0, false
+ }
}
}
- p.Typedef = conv.typedef
}
-func concat(a, b []string) []string {
- c := make([]string, len(a)+len(b))
- for i, s := range a {
- c[i] = s
+// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
+// Go equivalents, now that we have figured out the meaning of all
+// the xxx.
+func (p *Package) rewriteRef(f *File) {
+ // Assign mangled names.
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ n.Kind = "var"
+ }
+ if n.Mangle == "" {
+ n.Mangle = "_C" + n.Kind + "_" + n.Go
+ }
}
- for i, s := range b {
- c[i+len(a)] = s
+
+ // Now that we have all the name types filled in,
+ // scan through the Refs to identify the ones that
+ // are trying to do a ,err call. Also check that
+ // functions are only used in calls.
+ for _, r := range f.Ref {
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case "call", "call2":
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ r.Context = "type"
+ expr = r.Name.Type.Go
+ break
+ }
+ error(r.Pos(), "call of non-function C.%s", r.Name.Go)
+ break
+ }
+ if r.Context == "call2" {
+ if r.Name.FuncType.Result == nil {
+ error(r.Pos(), "assignment count mismatch: 2 = 0")
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = ast.NewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case "expr":
+ if r.Name.Kind == "func" {
+ error(r.Pos(), "must call C.%s", r.Name.Go)
+ }
+ if r.Name.Kind == "type" {
+ // Okay - might be new(T)
+ expr = r.Name.Type.Go
+ }
+ if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{X: expr}
+ }
+
+ case "type":
+ if r.Name.Kind != "type" {
+ error(r.Pos(), "expression C.%s used as type", r.Name.Go)
+ } else {
+ expr = r.Name.Type.Go
+ }
+ default:
+ if r.Name.Kind == "func" {
+ error(r.Pos(), "must call C.%s", r.Name.Go)
+ }
+ }
+ *r.Expr = expr
}
- return c
}
-// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and any messages
-// printed to standard error.
-func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) {
- machine := "-m32"
+// gccName returns the name of the compiler to run. Use $GCC if set in
+// the environment, otherwise just "gcc".
+
+func (p *Package) gccName() (ret string) {
+ if ret = os.Getenv("GCC"); ret == "" {
+ ret = "gcc"
+ }
+ return
+}
+
+// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
+func (p *Package) gccMachine() string {
if p.PtrSize == 8 {
- machine = "-m64"
+ return "-m64"
}
+ return "-m32"
+}
- tmp := "_cgo_.o"
- base := []string{
- "gcc",
- machine,
+const gccTmp = "_cgo_.o"
+
+// gccCmd returns the gcc command line to use for compiling
+// the input.
+func (p *Package) gccCmd() []string {
+ return []string{
+ p.gccName(),
+ p.gccMachine(),
"-Wall", // many warnings
"-Werror", // warnings are errors
- "-o" + tmp, // write object to tmp
+ "-o" + gccTmp, // write object to tmp
"-gdwarf-2", // generate DWARF v2 debugging symbols
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
"-c", // do not link
"-xc", // input language is C
"-", // read input from standard input
}
- _, stderr, ok := run(stdin, concat(base, p.GccOptions))
- if !ok {
- return nil, string(stderr)
- }
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and any messages
+// printed to standard error.
+func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
+ runGcc(stdin, append(p.gccCmd(), p.GccOptions...))
// Try to parse f as ELF and Mach-O and hope one works.
var f interface {
DWARF() (*dwarf.Data, os.Error)
}
var err os.Error
- if f, err = elf.Open(tmp); err != nil {
- if f, err = macho.Open(tmp); err != nil {
- fatal("cannot parse gcc output %s as ELF or Mach-O object", tmp)
+ if f, err = elf.Open(gccTmp); err != nil {
+ if f, err = macho.Open(gccTmp); err != nil {
+ if f, err = pe.Open(gccTmp); err != nil {
+ fatal("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
+ }
}
}
d, err := f.DWARF()
if err != nil {
- fatal("cannot load DWARF debug information from %s: %s", tmp, err)
+ fatal("cannot load DWARF debug information from %s: %s", gccTmp, err)
}
- return d, ""
+ return d
}
-func (p *Prog) gccPostProc(stdin []byte) string {
- machine := "-m32"
- if p.PtrSize == 8 {
- machine = "-m64"
+// gccDefines runs gcc -E -dM -xc - over the C program stdin
+// and returns the corresponding standard output, which is the
+// #defines that gcc encountered while processing the input
+// and its included files.
+func (p *Package) gccDefines(stdin []byte) string {
+ base := []string{p.gccName(), p.gccMachine(), "-E", "-dM", "-xc", "-"}
+ stdout, _ := runGcc(stdin, append(base, p.GccOptions...))
+ return stdout
+}
+
+// gccErrors runs gcc over the C program stdin and returns
+// the errors that gcc prints. That is, this function expects
+// gcc to fail.
+func (p *Package) gccErrors(stdin []byte) string {
+ // TODO(rsc): require failure
+ args := append(p.gccCmd(), p.GccOptions...)
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, _ := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
}
+ return string(stderr)
+}
- base := []string{"gcc", machine, "-E", "-dM", "-xc", "-"}
- stdout, stderr, ok := run(stdin, concat(base, p.GccOptions))
+// runGcc runs the gcc command line args with stdin on standard input.
+// If the command exits with a non-zero exit status, runGcc prints
+// details about what was run and exits.
+// Otherwise runGcc returns the data written to standard output and standard error.
+// Note that for some of the uses we expect useful data back
+// on standard error, but for those uses gcc must still exit 0.
+func runGcc(stdin []byte, args []string) (string, string) {
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, ok := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
if !ok {
- return string(stderr)
+ 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)
}
-
- return string(stdout)
+ return string(stdout), string(stderr)
}
// A typeConv is a translator from dwarf types to Go types
@@ -345,14 +596,14 @@ type typeConv struct {
string ast.Expr
ptrSize int64
-
- tagGen int
}
+var tagGen int
+var typedef = make(map[string]ast.Expr)
+
func (c *typeConv) Init(ptrSize int64) {
c.ptrSize = ptrSize
c.m = make(map[dwarf.Type]*Type)
- c.typedef = make(map[string]ast.Expr)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
@@ -388,7 +639,7 @@ func base(dt dwarf.Type) dwarf.Type {
}
// Map from dwarf text names to aliases we use in package "C".
-var cnameMap = map[string]string{
+var dwarfToName = map[string]string{
"long int": "long",
"long unsigned int": "ulong",
"unsigned int": "uint",
@@ -415,6 +666,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = dtype.Common().Name
t.EnumValues = nil
c.m[dtype] = t
+
if t.Size < 0 {
// Unsized types are [0]byte
t.Size = 0
@@ -550,16 +802,16 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
// Have to give it a name to simulate C "struct foo" references.
tag := dt.StructName
if tag == "" {
- tag = "__" + strconv.Itoa(c.tagGen)
- c.tagGen++
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
} else if t.C == "" {
t.C = dt.Kind + " " + tag
}
- name := c.Ident("_C" + dt.Kind + "_" + tag)
+ name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
t.Go = name // publish before recursive calls
switch dt.Kind {
case "union", "class":
- c.typedef[name.Name()] = c.Opaque(t.Size)
+ typedef[name.Name] = c.Opaque(t.Size)
if t.C == "" {
t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size)
}
@@ -569,7 +821,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = csyntax
}
t.Align = align
- c.typedef[name.Name()] = g
+ typedef[name.Name] = g
}
case *dwarf.TypedefType:
@@ -583,13 +835,13 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Align = c.ptrSize
break
}
- name := c.Ident("_C_" + dt.Name)
+ name := c.Ident("_Ctypedef_" + dt.Name)
t.Go = name // publish before recursive call
sub := c.Type(dt.Type)
t.Size = sub.Size
t.Align = sub.Align
- if _, ok := c.typedef[name.Name()]; !ok {
- c.typedef[name.Name()] = sub.Go
+ if _, ok := typedef[name.Name]; !ok {
+ typedef[name.Name] = sub.Go
}
case *dwarf.UcharType:
@@ -628,12 +880,12 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
s := dtype.Common().Name
if s != "" {
- if ss, ok := cnameMap[s]; ok {
+ if ss, ok := dwarfToName[s]; ok {
s = ss
}
s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces
- name := c.Ident("_C_" + s)
- c.typedef[name.Name()] = t.Go
+ name := c.Ident("_Ctype_" + s)
+ typedef[name.Name] = t.Go
t.Go = name
}
}
@@ -710,7 +962,9 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
}
// Identifier
-func (c *typeConv) Ident(s string) *ast.Ident { return ast.NewIdent(s) }
+func (c *typeConv) Ident(s string) *ast.Ident {
+ return ast.NewIdent(s)
+}
// Opaque type of n bytes.
func (c *typeConv) Opaque(n int64) ast.Expr {
@@ -736,13 +990,14 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
return fld
}
-// Struct conversion
+// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
- csyntax = "struct { "
+ var buf bytes.Buffer
+ buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
off := int64(0)
- // Mangle struct fields that happen to be named Go keywords into
+ // Rename struct fields that happen to be named Go keywords into
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
// be mangled. Any existing identifier that already has the same name on
// the C-side will cause the Go-mangled version to be prefixed with _.
@@ -783,7 +1038,10 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
off += t.Size
- csyntax += t.C + " " + f.Name + "; "
+ buf.WriteString(t.C)
+ buf.WriteString(" ")
+ buf.WriteString(f.Name)
+ buf.WriteString("; ")
if t.Align > align {
align = t.Align
}
@@ -795,7 +1053,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
if off != dt.ByteSize {
fatal("struct size calculation error")
}
- csyntax += "}"
+ buf.WriteString("}")
+ csyntax = buf.String()
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return
}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 070146c9a..942bda5f4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -11,13 +11,95 @@
package main
import (
+ "crypto/md5"
+ "flag"
"fmt"
"go/ast"
+ "go/token"
+ "io"
"os"
+ "reflect"
"strings"
)
-func usage() { fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n") }
+// A Package collects information about the package we're going to write.
+type Package struct {
+ PackageName string // name of package
+ PackagePath string
+ PtrSize int64
+ GccOptions []string
+ Written map[string]bool
+ Name map[string]*Name // accumulated Name from Files
+ Typedef map[string]ast.Expr // accumulated Typedef from Files
+ ExpFunc []*ExpFunc // accumulated ExpFunc from Files
+ Decl []ast.Decl
+ GoFiles []string // list of Go files
+ GccFiles []string // list of gcc output files
+}
+
+// A File collects information about a single Go input file.
+type File struct {
+ AST *ast.File // parsed AST
+ Package string // Package name
+ Preamble string // C preamble (doc comment on import "C")
+ Ref []*Ref // all references to C.xxx in AST
+ ExpFunc []*ExpFunc // exported functions for this file
+ Name map[string]*Name // map from Go name to Name
+ Typedef map[string]ast.Expr // translations of all necessary types from C
+}
+
+// A Ref refers to an expression of the form C.xxx in the AST.
+type Ref struct {
+ Name *Name
+ Expr *ast.Expr
+ Context string // "type", "expr", "call", or "call2"
+}
+
+func (r *Ref) Pos() token.Pos {
+ return (*r.Expr).Pos()
+}
+
+// A Name collects information about C.xxx.
+type Name struct {
+ Go string // name used in Go referring to package C
+ Mangle string // name used in generated Go
+ C string // name used in C
+ Define string // #define expansion
+ Kind string // "const", "type", "var", "func", "not-type"
+ Type *Type // the type of xxx
+ FuncType *FuncType
+ AddError bool
+ Const string // constant definition
+}
+
+// A ExpFunc is an exported function, callable from C.
+// Such functions are identified in the Go input file
+// by doc comments containing the line //export ExpName
+type ExpFunc struct {
+ Func *ast.FuncDecl
+ ExpName string // name to use from C
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+ Size int64
+ Align int64
+ C string
+ Go ast.Expr
+ EnumValues map[string]int64
+}
+
+// A FuncType collects information about a function type in both the C and Go worlds.
+type FuncType struct {
+ Params []*Type
+ Result *Type
+ Go *ast.FuncType
+}
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n")
+ os.Exit(2)
+}
var ptrSizeMap = map[string]int64{
"386": 4,
@@ -25,43 +107,60 @@ var ptrSizeMap = map[string]int64{
"arm": 4,
}
-var expandName = 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",
-}
+var cPrefix string
+
+var fset = token.NewFileSet()
+
+var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
func main() {
- args := os.Args
- if len(args) < 2 {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *dynobj != "" {
+ // cgo -dynimport is essentially a separate helper command
+ // built into the cgo binary. It scans a gcc-produced executable
+ // and dumps information about the imported symbols and the
+ // imported libraries. The Make.pkg rules for cgo prepare an
+ // appropriate executable and then use its import information
+ // instead of needing to make the linkers duplicate all the
+ // specialized knowledge gcc has about where to look for imported
+ // symbols and which ones to use.
+ syms, imports := dynimport(*dynobj)
+ for _, sym := range syms {
+ fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "")
+ }
+ for _, p := range imports {
+ fmt.Printf("#pragma dynimport %s %s %q\n", "_", "_", p)
+ }
+ return
+ }
+
+ args := flag.Args()
+ if len(args) < 1 {
usage()
- os.Exit(2)
}
// Find first arg that looks like a go file and assume everything before
// that are options to pass to gcc.
var i int
- for i = len(args) - 1; i > 0; i-- {
- if !strings.HasSuffix(args[i], ".go") {
+ for i = len(args); i > 0; i-- {
+ if !strings.HasSuffix(args[i-1], ".go") {
break
}
}
-
- i += 1
-
- gccOptions, goFiles := args[1:i], args[i:]
+ if i == len(args) {
+ usage()
+ }
+ gccOptions, goFiles := args[0:i], args[i:]
arch := os.Getenv("GOARCH")
if arch == "" {
fatal("$GOARCH is not set")
}
- ptrSize, ok := ptrSizeMap[arch]
- if !ok {
- fatal("unknown architecture %s", arch)
+ ptrSize := ptrSizeMap[arch]
+ if ptrSize == 0 {
+ fatal("unknown $GOARCH %q", arch)
}
// Clear locale variables so gcc emits English errors [sic].
@@ -69,75 +168,82 @@ func main() {
os.Setenv("LC_ALL", "C")
os.Setenv("LC_CTYPE", "C")
- p := new(Prog)
-
- p.PtrSize = ptrSize
- p.GccOptions = gccOptions
- p.Vardef = make(map[string]*Type)
- p.Funcdef = make(map[string]*FuncType)
- p.Enumdef = make(map[string]int64)
- p.Constdef = make(map[string]string)
- p.OutDefs = make(map[string]bool)
+ p := &Package{
+ PtrSize: ptrSize,
+ GccOptions: gccOptions,
+ Written: make(map[string]bool),
+ }
+ // Need a unique prefix for the global C symbols that
+ // we use to coordinate between gcc and ourselves.
+ // We already put _cgo_ at the beginning, so the main
+ // concern is other cgo wrappers for the same functions.
+ // Use the beginning of the md5 of the input to disambiguate.
+ h := md5.New()
for _, input := range goFiles {
- // Reset p.Preamble so that we don't end up with conflicting headers / defines
- p.Preamble = builtinProlog
- openProg(input, p)
- for _, cref := range p.Crefs {
- // Convert C.ulong to C.unsigned long, etc.
- if expand, ok := expandName[cref.Name]; ok {
- cref.Name = expand
- }
+ f, err := os.Open(input, os.O_RDONLY, 0)
+ if err != nil {
+ fatal("%s", err)
}
- p.loadDebugInfo()
- for _, cref := range p.Crefs {
+ io.Copy(h, f)
+ f.Close()
+ }
+ cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
+
+ for _, input := range goFiles {
+ f := new(File)
+ // Reset f.Preamble so that we don't end up with conflicting headers / defines
+ f.Preamble = ""
+ f.ReadGo(input)
+ p.Translate(f)
+ for _, cref := range f.Ref {
switch cref.Context {
- case "const":
- // This came from a #define and we'll output it later.
- *cref.Expr = ast.NewIdent(cref.Name)
- break
- case "call":
- if !cref.TypeName {
- // Is an actual function call.
- pos := (*cref.Expr).Pos()
- *cref.Expr = &ast.Ident{Position: pos, Obj: ast.NewObj(ast.Err, pos, "_C_"+cref.Name)}
- p.Funcdef[cref.Name] = cref.FuncType
- break
- }
- *cref.Expr = cref.Type.Go
- case "expr":
- if cref.TypeName {
- error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name)
- }
- // If the expression refers to an enumerated value, then
- // place the identifier for the value and add it to Enumdef so
- // it will be declared as a constant in the later stage.
- if cref.Type.EnumValues != nil {
- *cref.Expr = ast.NewIdent(cref.Name)
- p.Enumdef[cref.Name] = cref.Type.EnumValues[cref.Name]
+ case "call", "call2":
+ if cref.Name.Kind != "type" {
break
}
- // Reference to C variable.
- // We declare a pointer and arrange to have it filled in.
- *cref.Expr = &ast.StarExpr{X: ast.NewIdent("_C_" + cref.Name)}
- p.Vardef[cref.Name] = cref.Type
- case "type":
- if !cref.TypeName {
- error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name)
- }
- *cref.Expr = cref.Type.Go
+ *cref.Expr = cref.Name.Type.Go
}
}
if nerrors > 0 {
os.Exit(2)
}
- pkg := p.Package
+ pkg := f.Package
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
pkg = dir + "/" + pkg
}
p.PackagePath = pkg
- p.writeOutput(input)
+ p.writeOutput(f, input)
+
+ p.Record(f)
}
p.writeDefs()
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+}
+
+// Record what needs to be recorded about f.
+func (p *Package) Record(f *File) {
+ if p.PackageName == "" {
+ p.PackageName = f.Package
+ } else if p.PackageName != f.Package {
+ error(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
+ }
+
+ if p.Name == nil {
+ p.Name = f.Name
+ } else {
+ for k, v := range f.Name {
+ if p.Name[k] == nil {
+ p.Name[k] = v
+ } else if !reflect.DeepEqual(p.Name[k], v) {
+ error(token.NoPos, "inconsistent definitions for C.%s", k)
+ }
+ }
+ }
+
+ p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ p.Decl = append(p.Decl, f.AST.Decls...)
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 7cdf483f0..c3f9ae60b 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -5,6 +5,9 @@
package main
import (
+ "bytes"
+ "debug/elf"
+ "debug/macho"
"fmt"
"go/ast"
"go/printer"
@@ -13,30 +16,9 @@ import (
"strings"
)
-func creat(name string) *os.File {
- f, err := os.Open(name, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666)
- if err != nil {
- fatal("%s", err)
- }
- return f
-}
-
-func slashToUnderscore(c int) int {
- if c == '/' {
- c = '_'
- }
- return c
-}
-
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Prog) writeDefs() {
- pkgroot := os.Getenv("GOROOT") + "/pkg/" + os.Getenv("GOOS") + "_" + os.Getenv("GOARCH")
- path := p.PackagePath
- if !strings.HasPrefix(path, "/") {
- path = pkgroot + "/" + path
- }
-
+func (p *Package) writeDefs() {
// The path for the shared object is slash-free so that ELF loaders
// will treat it as a relative path. We rewrite slashes to underscores.
sopath := "cgo_" + strings.Map(slashToUnderscore, p.PackagePath)
@@ -48,229 +30,305 @@ func (p *Prog) writeDefs() {
fgo2 := creat("_cgo_gotypes.go")
fc := creat("_cgo_defun.c")
+ fm := creat("_cgo_main.c")
+
+ // 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")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
// pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n")
- fmt.Fprintf(fgo2, "package %s\n\n", p.Package)
+ fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
+ fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
+ fmt.Fprintf(fgo2, "import \"os\"\n\n")
+ fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n")
fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n")
+ fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n")
- for name, def := range p.Typedef {
+ for name, def := range typedef {
fmt.Fprintf(fgo2, "type %s ", name)
- printer.Fprint(fgo2, def)
+ printer.Fprint(fgo2, fset, def)
fmt.Fprintf(fgo2, "\n")
}
- fmt.Fprintf(fgo2, "type _C_void [0]byte\n")
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+
+ fmt.Fprintf(fc, cProlog)
+
+ var cVars []string
+ for _, n := range p.Name {
+ if n.Kind != "var" {
+ continue
+ }
+ cVars = append(cVars, n.C)
- fmt.Fprintf(fc, cProlog, soprefix, soprefix, soprefix, soprefix, soprefix)
+ fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+ fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+
+ fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+ fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
+ fmt.Fprintf(fc, "\n")
- for name, def := range p.Vardef {
- fmt.Fprintf(fc, "#pragma dynimport ·_C_%s %s \"%s%s.so\"\n", name, name, soprefix, sopath)
- fmt.Fprintf(fgo2, "var _C_%s ", name)
- printer.Fprint(fgo2, &ast.StarExpr{X: def.Go})
+ fmt.Fprintf(fgo2, "var %s ", n.Mangle)
+ printer.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
fmt.Fprintf(fgo2, "\n")
}
fmt.Fprintf(fc, "\n")
- for name, value := range p.Constdef {
- fmt.Fprintf(fgo2, "const %s = %s\n", name, value)
- }
-
- for name, value := range p.Enumdef {
- fmt.Fprintf(fgo2, "const %s = %d\n", name, value)
+ for _, n := range p.Name {
+ if n.Const != "" {
+ fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
+ }
}
fmt.Fprintf(fgo2, "\n")
- for name, def := range p.Funcdef {
- // Go func declaration.
- d := &ast.FuncDecl{
- Name: ast.NewIdent("_C_" + name),
- Type: def.Go,
+ for _, n := range p.Name {
+ if n.FuncType != nil {
+ p.writeDefsFunc(fc, fgo2, n, soprefix, sopath)
}
- printer.Fprint(fgo2, d)
- fmt.Fprintf(fgo2, "\n")
+ }
- if name == "CString" || name == "GoString" {
- // The builtins are already defined in the C prolog.
- continue
+ p.writeExports(fgo2, fc, fm)
+
+ fgo2.Close()
+ fc.Close()
+}
+
+func dynimport(obj string) (syms, imports []string) {
+ var f interface {
+ ImportedLibraries() ([]string, os.Error)
+ ImportedSymbols() ([]string, os.Error)
+ }
+ var isMacho bool
+ var err1, err2 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)
}
+ isMacho = true
+ }
- // Construct a gcc struct matching the 6c argument frame.
- // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
- // These assumptions are checked by the gccProlog.
- // Also assumes that 6c convention is to word-align the
- // input and output parameters.
- structType := "struct {\n"
- off := int64(0)
- npad := 0
- for i, t := range def.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
+ var err os.Error
+ syms, err = f.ImportedSymbols()
+ if err != nil {
+ fatal("cannot load dynamic symbols: %v", err)
+ }
+ if isMacho {
+ // remove leading _ that OS X insists on
+ for i, s := range syms {
+ if len(s) >= 2 && s[0] == '_' {
+ syms[i] = s[1:]
}
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ }
+
+ imports, err = f.ImportedLibraries()
+ if err != nil {
+ fatal("cannot load dynamic imports: %v", err)
+ }
+
+ return
+}
+
+// Construct a gcc struct matching the 6c argument frame.
+// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
+// These assumptions are checked by the gccProlog.
+// Also assumes that 6c convention is to word-align the
+// input and output parameters.
+func (p *Package) structType(n *Name) (string, int64) {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "struct {\n")
+ off := int64(0)
+ for i, t := range n.FuncType.Params {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
- npad++
- }
- if t := def.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s r;\n", t.C)
- off += t.Size
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ fmt.Fprintf(&buf, "\t\t%s p%d;\n", t.C, i)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if t := n.FuncType.Result; t != nil {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
- npad++
}
- if len(def.Params) == 0 && def.Result == nil {
- structType += "\t\tchar unused;\n" // avoid empty struct
- off++
+ qual := ""
+ if t.C[len(t.C)-1] == '*' {
+ qual = "const "
}
- structType += "\t}"
- argSize := off
+ fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if n.AddError {
+ fmt.Fprint(&buf, "\t\tvoid *e[2]; /* os.Error */\n")
+ off += 2 * p.PtrSize
+ }
+ if off == 0 {
+ fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
+ off++
+ }
+ fmt.Fprintf(&buf, "\t}")
+ return buf.String(), off
+}
- // C wrapper calls into gcc, passing a pointer to the argument frame.
- // Also emit #pragma to get a pointer to the gcc wrapper.
- fmt.Fprintf(fc, "#pragma dynimport _cgo_%s _cgo_%s \"%s%s.so\"\n", name, name, soprefix, sopath)
- fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- fmt.Fprintf(fc, "·_C_%s(struct{uint8 x[%d];}p)\n", name, argSize)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name)
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
+func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name, soprefix, sopath string) {
+ name := n.Go
+ gtype := n.FuncType.Go
+ if n.AddError {
+ // Add "os.Error" to return type list.
+ // Type list is known to be 0 or 1 element - it's a C function.
+ err := &ast.Field{Type: ast.NewIdent("os.Error")}
+ l := gtype.Results.List
+ if len(l) == 0 {
+ l = []*ast.Field{err}
+ } else {
+ l = []*ast.Field{l[0], err}
+ }
+ t := new(ast.FuncType)
+ *t = *gtype
+ t.Results = &ast.FieldList{List: l}
+ gtype = t
}
- p.writeExports(fgo2, fc)
+ // Go func declaration.
+ d := &ast.FuncDecl{
+ Name: ast.NewIdent(n.Mangle),
+ Type: gtype,
+ }
+ printer.Fprint(fgo2, fset, d)
+ fmt.Fprintf(fgo2, "\n")
- fgo2.Close()
- fc.Close()
+ if name == "CString" || name == "GoString" || name == "GoStringN" {
+ // The builtins are already defined in the C prolog.
+ return
+ }
+
+ var argSize int64
+ _, argSize = p.structType(n)
+
+ // C wrapper calls into gcc, passing a pointer to the argument frame.
+ fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fc, "\n")
+ fmt.Fprintf(fc, "void\n")
+ fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize)
+ fmt.Fprintf(fc, "{\n")
+ fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
+ if n.AddError {
+ // gcc leaves errno in first word of interface at end of p.
+ // check whether it is zero; if so, turn interface into nil.
+ // if not, turn interface into errno.
+ // Go init function initializes ·_Cerrno with an os.Errno
+ // for us to copy.
+ fmt.Fprintln(fc, ` {
+ int32 e;
+ void **v;
+ v = (void**)(&p+1) - 2; /* v = final two void* of p */
+ e = *(int32*)v;
+ v[0] = (void*)0xdeadbeef;
+ v[1] = (void*)0xdeadbeef;
+ if(e == 0) {
+ /* nil interface */
+ v[0] = 0;
+ v[1] = 0;
+ } else {
+ ·_Cerrno(v, e); /* fill in v as os.Error for errno e */
+ }
+ }`)
+ }
+ fmt.Fprintf(fc, "}\n")
+ fmt.Fprintf(fc, "\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Prog) writeOutput(srcfile string) {
+func (p *Package) writeOutput(f *File, srcfile string) {
base := srcfile
if strings.HasSuffix(base, ".go") {
base = base[0 : len(base)-3]
}
+ base = strings.Map(slashToUnderscore, base)
fgo1 := creat(base + ".cgo1.go")
fgcc := creat(base + ".cgo2.c")
+ p.GoFiles = append(p.GoFiles, base+".cgo1.go")
+ p.GccFiles = append(p.GccFiles, base+".cgo2.c")
+
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
- fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n")
+ fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
- printer.Fprint(fgo1, p.AST)
+ printer.Fprint(fgo1, fset, f.AST)
// While we process the vars and funcs, also write 6c and gcc output.
// Gcc output starts with the preamble.
- fmt.Fprintf(fgcc, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
- for name, def := range p.Funcdef {
- _, ok := p.OutDefs[name]
- if name == "CString" || name == "GoString" || ok {
- // The builtins are already defined in the C prolog, and we don't
- // want to duplicate function definitions we've already done.
- continue
- }
- p.OutDefs[name] = true
-
- // Construct a gcc struct matching the 6c argument frame.
- // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
- // These assumptions are checked by the gccProlog.
- // Also assumes that 6c convention is to word-align the
- // input and output parameters.
- structType := "struct {\n"
- off := int64(0)
- npad := 0
- for i, t := range def.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
+ for _, n := range f.Name {
+ if n.FuncType != nil {
+ p.writeOutputFunc(fgcc, n)
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if t := def.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s r;\n", t.C)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if len(def.Params) == 0 && def.Result == nil {
- structType += "\t\tchar unused;\n" // avoid empty struct
- off++
- }
- structType += "\t}"
-
- // Gcc wrapper unpacks the C argument struct
- // and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
- fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name)
- fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType)
- fmt.Fprintf(fgcc, "\t")
- if def.Result != nil {
- fmt.Fprintf(fgcc, "a->r = ")
- }
- fmt.Fprintf(fgcc, "%s(", name)
- for i := range def.Params {
- if i > 0 {
- fmt.Fprintf(fgcc, ", ")
- }
- fmt.Fprintf(fgcc, "a->p%d", i)
- }
- fmt.Fprintf(fgcc, ");\n")
- fmt.Fprintf(fgcc, "}\n")
- fmt.Fprintf(fgcc, "\n")
}
fgo1.Close()
fgcc.Close()
}
-// Write out the various stubs we need to support functions exported
-// from Go so that they are callable from C.
-func (p *Prog) writeExports(fgo2, fc *os.File) {
- if len(p.ExpFuncs) == 0 {
+func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
+ name := n.Mangle
+ if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] {
+ // The builtins are already defined in the C prolog, and we don't
+ // want to duplicate function definitions we've already done.
return
}
+ p.Written[name] = true
+
+ ctype, _ := p.structType(n)
+
+ // Gcc wrapper unpacks the C argument struct
+ // and calls the actual C function.
+ fmt.Fprintf(fgcc, "void\n")
+ fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fgcc, "{\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
+ fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ }
+ fmt.Fprintf(fgcc, "\t%s *a = v;\n", ctype)
+ fmt.Fprintf(fgcc, "\t")
+ if n.FuncType.Result != nil {
+ fmt.Fprintf(fgcc, "a->r = ")
+ }
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "a->p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
+ }
+ fmt.Fprintf(fgcc, "}\n")
+ fmt.Fprintf(fgcc, "\n")
+}
+// Write out the various stubs we need to support functions exported
+// from Go so that they are callable from C.
+func (p *Package) writeExports(fgo2, fc, fm *os.File) {
fgcc := creat("_cgo_export.c")
fgcch := creat("_cgo_export.h")
@@ -280,17 +338,17 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
- for _, exp := range p.ExpFuncs {
+ for _, exp := range p.ExpFunc {
fn := exp.Func
// Construct a gcc struct matching the 6c argument and
// result frame.
- structType := "struct {\n"
+ ctype := "struct {\n"
off := int64(0)
npad := 0
if fn.Recv != nil {
t := p.cgoType(fn.Recv.List[0].Type)
- structType += fmt.Sprintf("\t\t%s recv;\n", t.C)
+ ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
off += t.Size
}
fntype := fn.Type
@@ -299,16 +357,16 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
+ ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
@@ -317,24 +375,24 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
off += pad
npad++
}
- structType += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
+ ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
- if structType == "struct {\n" {
- structType += "\t\tchar unused;\n" // avoid empty struct
+ if ctype == "struct {\n" {
+ ctype += "\t\tchar unused;\n" // avoid empty struct
off++
}
- structType += "\t}"
+ ctype += "\t}"
// Get the return type of the wrapper function
// compiled by gcc.
@@ -370,10 +428,10 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
s += ")"
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
- fmt.Fprintf(fgcc, "extern _cgoexp_%s(void *, int);\n", exp.ExpName)
+ fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s a;\n", structType)
+ fmt.Fprintf(fgcc, "\t%s a;\n", ctype)
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
@@ -384,7 +442,7 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
func(i int, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp_%s, &a, (int) sizeof a);\n", exp.ExpName)
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, (int) sizeof a);\n", cPrefix, exp.ExpName)
if gccResult != "void" {
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
@@ -399,27 +457,28 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by 6c/8c
- goname := exp.Func.Name.Name()
+ goname := exp.Func.Name.Name
if fn.Recv != nil {
- goname = "_cgoexpwrap_" + fn.Recv.List[0].Names[0].Name() + "_" + goname
+ goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "#pragma dynexport _cgoexp_%s _cgoexp_%s\n", exp.ExpName, exp.ExpName)
fmt.Fprintf(fc, "extern void ·%s();\n", goname)
fmt.Fprintf(fc, "\nvoid\n")
- fmt.Fprintf(fc, "_cgoexp_%s(void *a, int32 n)\n", exp.ExpName)
+ fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\tcgocallback(·%s, a, n);\n", goname)
+ fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
fmt.Fprintf(fc, "}\n")
+ fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
+
// Calling a function with a receiver from C requires
// a Go wrapper function.
if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname)
- printer.Fprint(fgo2, fn.Recv.List[0].Type)
+ printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
forFieldList(fntype.Params,
func(i int, atype ast.Expr) {
- fmt.Fprintf(fgo2, ", p%d", i)
- printer.Fprint(fgo2, atype)
+ fmt.Fprintf(fgo2, ", p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
@@ -429,7 +488,7 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- printer.Fprint(fgo2, atype)
+ printer.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
@@ -493,7 +552,7 @@ var goTypes = map[string]*Type{
}
// Map an ast type to a Type.
-func (p *Prog) cgoType(e ast.Expr) *Type {
+func (p *Package) cgoType(e ast.Expr) *Type {
switch t := e.(type) {
case *ast.StarExpr:
x := p.cgoType(t.X)
@@ -515,7 +574,7 @@ func (p *Prog) cgoType(e ast.Expr) *Type {
case *ast.Ident:
// Look up the type in the top level declarations.
// TODO: Handle types defined within a function.
- for _, d := range p.AST.Decls {
+ for _, d := range p.Decl {
gd, ok := d.(*ast.GenDecl)
if !ok || gd.Tok != token.TYPE {
continue
@@ -525,30 +584,35 @@ func (p *Prog) cgoType(e ast.Expr) *Type {
if !ok {
continue
}
- if ts.Name.Name() == t.Name() {
+ if ts.Name.Name == t.Name {
return p.cgoType(ts.Type)
}
}
}
- for name, def := range p.Typedef {
- if name == t.Name() {
+ for name, def := range typedef {
+ if name == t.Name {
return p.cgoType(def)
}
}
- if t.Name() == "uintptr" {
+ if t.Name == "uintptr" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "uintptr"}
}
- if t.Name() == "string" {
+ if t.Name == "string" {
return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: "GoString"}
}
- if r, ok := goTypes[t.Name()]; ok {
+ if r, ok := goTypes[t.Name]; ok {
if r.Align > p.PtrSize {
r.Align = p.PtrSize
}
return r
}
+ case *ast.SelectorExpr:
+ id, ok := t.X.(*ast.Ident)
+ if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "void*"}
+ }
}
- error(e.Pos(), "unrecognized Go type %v", e)
+ error(e.Pos(), "unrecognized Go type %T", e)
return &Type{Size: 4, Align: 4, C: "int"}
}
@@ -568,11 +632,15 @@ typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
+
+#include <errno.h>
+#include <string.h>
`
const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
_GoString_ GoString(char *p);
+_GoString_ GoStringN(char *p, int l);
char *CString(_GoString_);
`
@@ -580,24 +648,27 @@ const cProlog = `
#include "runtime.h"
#include "cgocall.h"
-#pragma dynimport initcgo initcgo "%slibcgo.so"
-#pragma dynimport libcgo_thread_start libcgo_thread_start "%slibcgo.so"
-#pragma dynimport libcgo_set_scheduler libcgo_set_scheduler "%slibcgo.so"
-#pragma dynimport _cgo_malloc _cgo_malloc "%slibcgo.so"
-#pragma dynimport _cgo_free _cgo_free "%slibcgo.so"
+void ·_Cerrno(void*, int32);
+
+void
+·_Cfunc_GoString(int8 *p, String s)
+{
+ s = runtime·gostring((byte*)p);
+ FLUSH(&s);
+}
void
-·_C_GoString(int8 *p, String s)
+·_Cfunc_GoStringN(int8 *p, int32 l, String s)
{
- s = gostring((byte*)p);
+ s = runtime·gostringn((byte*)p, l);
FLUSH(&s);
}
void
-·_C_CString(String s, int8 *p)
+·_Cfunc_CString(String s, int8 *p)
{
- p = cmalloc(s.len+1);
- mcpy((byte*)p, s.str, s.len);
+ p = runtime·cmalloc(s.len+1);
+ runtime·mcpy((byte*)p, s.str, s.len);
p[s.len] = 0;
FLUSH(&p);
}
@@ -610,6 +681,7 @@ typedef unsigned char uchar;
typedef unsigned short ushort;
typedef long long int64;
typedef unsigned long long uint64;
+typedef __SIZE_TYPE__ uintptr;
typedef struct { char *p; int n; } GoString;
typedef void *GoMap;
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 95067039c..a6f509dc4 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -12,16 +12,6 @@ import (
"os"
)
-// A ByteReaderAt implements io.ReadAt using a slice of bytes.
-type ByteReaderAt []byte
-
-func (r ByteReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
- if off >= int64(len(r)) || off < 0 {
- return 0, os.EOF
- }
- return copy(p, r[off:]), nil
-}
-
// run runs the command argv, feeding in stdin on standard input.
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
@@ -55,9 +45,8 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
w0.Close()
c <- true
}()
- var xstdout []byte // TODO(rsc): delete after 6g can take address of out parameter
go func() {
- xstdout, _ = ioutil.ReadAll(r1)
+ stdout, _ = ioutil.ReadAll(r1)
r1.Close()
c <- true
}()
@@ -65,7 +54,6 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
r2.Close()
<-c
<-c
- stdout = xstdout
w, err := os.Wait(pid, 0)
if err != nil {
@@ -77,18 +65,45 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
// Die with an error message.
func fatal(msg string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, msg+"\n", args)
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(2)
}
var nerrors int
-var noPos token.Position
-func error(pos token.Position, msg string, args ...interface{}) {
+func error(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
- fmt.Fprintf(os.Stderr, "%s: ", pos)
+ fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
}
- fmt.Fprintf(os.Stderr, msg, args)
+ fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")
}
+
+// isName returns true if s is a valid C identifier
+func isName(s string) bool {
+ for i, v := range s {
+ if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
+ return false
+ }
+ if i == 0 && '0' <= v && v <= '9' {
+ return false
+ }
+ }
+ return s != ""
+}
+
+func creat(name string) *os.File {
+ f, err := os.Open(name, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666)
+ if err != nil {
+ fatal("%s", err)
+ }
+ return f
+}
+
+func slashToUnderscore(c int) int {
+ if c == '/' {
+ c = '_'
+ }
+ return c
+}
diff --git a/src/cmd/clean.bash b/src/cmd/clean.bash
index 9317b8ae5..6349919a8 100644
--- a/src/cmd/clean.bash
+++ b/src/cmd/clean.bash
@@ -3,11 +3,9 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-GOBIN="${GOBIN:-$HOME/bin}"
-
for i in cc 6l 6a 6c 8l 8a 8c 8g 5l 5a 5c 5g gc 6g gopack nm cgo cov ebnflint godefs godoc gofmt goinstall gotest goyacc hgpatch prof
do
cd $i
- "$GOBIN"/gomake clean
+ gomake clean
cd ..
done
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
index 58cb2302c..fdeb14636 100644
--- a/src/cmd/cov/Makefile
+++ b/src/cmd/cov/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
# The directory is cov because the source is portable and general.
# We call the binary 6cov to avoid confusion and because this binary
@@ -16,15 +17,22 @@ OFILES=\
HFILES=\
tree.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
+NOINSTALL=1
+include ../../Make.ccmd
-install: install-$(shell uname | tr A-Z a-z)
+ifeq ($(GOOS),windows)
+NAME=windows
+else
+NAME=$(shell uname | tr A-Z a-z)
+endif
+
+install: install-$(NAME)
install-linux: install-default
install-freebsd: install-default
+install-windows: install-default
# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
install-darwin: $(TARG)
@@ -32,5 +40,3 @@ install-darwin: $(TARG)
install-default: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
index 1b3138a7f..5ff22c00a 100644
--- a/src/cmd/cov/main.c
+++ b/src/cmd/cov/main.c
@@ -81,7 +81,7 @@ ran(uvlong pc, uvlong epc)
key.epc = pc+1;
r = treeget(&breakpoints, &key);
if(r == nil)
- sysfatal("unchecked breakpoint at %#lux+%d", pc, (int)(epc-pc));
+ sysfatal("unchecked breakpoint at %#llux+%d", pc, (int)(epc-pc));
// Might be that the tail of the sequence
// was run already, so r->epc is before the end.
diff --git a/src/cmd/ebnflint/Makefile b/src/cmd/ebnflint/Makefile
index 8cb9fd821..8f030aaef 100644
--- a/src/cmd/ebnflint/Makefile
+++ b/src/cmd/ebnflint/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=ebnflint
GOFILES=\
@@ -11,5 +11,5 @@ GOFILES=\
include ../../Make.cmd
test: $(TARG)
- $(QUOTED_GOBIN)/$(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
+ $(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
index 3dfa71f07..10cb5b387 100644
--- a/src/cmd/ebnflint/ebnflint.go
+++ b/src/cmd/ebnflint/ebnflint.go
@@ -10,12 +10,14 @@ import (
"flag"
"fmt"
"go/scanner"
+ "go/token"
"io/ioutil"
"os"
"path"
)
+var fset = token.NewFileSet()
var start = flag.String("start", "Start", "name of start production")
@@ -92,12 +94,12 @@ func main() {
src = extractEBNF(src)
}
- grammar, err := ebnf.Parse(filename, src)
+ grammar, err := ebnf.Parse(fset, filename, src)
if err != nil {
scanner.PrintError(os.Stderr, err)
}
- if err = ebnf.Verify(grammar, *start); err != nil {
+ if err = ebnf.Verify(fset, grammar, *start); err != nil {
scanner.PrintError(os.Stderr, err)
}
}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index 46dc6dfbc..dbfd86474 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-LIB=\
- gc.a$O\
+LIB=gc.a
HFILES=\
go.h\
@@ -43,16 +43,10 @@ OFILES=\
walk.$O\
y1.tab.$O\
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
+NOINSTALL=1
+include ../../Make.clib
-$(OFILES): $(HFILES)
-
-y.tab.h: $(YFILES)
- LANG=C LANGUAGE="en_US.UTF8" bison -v -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
+install: $(LIB)
y1.tab.c: y.tab.c # make yystate global, yytname mutable
cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c
@@ -70,7 +64,4 @@ subr.$O: opnames.h
opnames.h: mkopnames go.h
./mkopnames go.h >opnames.h
-clean:
- rm -f *.[568o] enam.c [568].out a.out y.tab.h y.tab.c y1.tab.c y.output yerr.h $(LIB) mkbuiltin1 builtin.c _builtin.c opnames.h
-
-install: $(LIB)
+CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 1b9112d69..a3785e871 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -7,8 +7,8 @@
/*
* machine size and rounding
* alignment is dictated around
- * the size of a pointer, set in belexinit
- * (see ../6g/align.c).
+ * the size of a pointer, set in betypeinit
+ * (see ../6g/galign.c).
*/
static int defercalc;
@@ -16,15 +16,9 @@ static int defercalc;
uint32
rnd(uint32 o, uint32 r)
{
- if(maxround == 0)
+ if(r < 1 || r > 8 || (r&(r-1)) != 0)
fatal("rnd");
-
- if(r > maxround)
- r = maxround;
- if(r != 0)
- while(o%r != 0)
- o++;
- return o;
+ return (o+r-1)&~(r-1);
}
static void
@@ -43,29 +37,24 @@ offmod(Type *t)
}
static uint32
-arrayelemwidth(Type *t)
-{
-
- while(t->etype == TARRAY && t->bound >= 0)
- t = t->type;
- return t->width;
-}
-
-static uint32
widstruct(Type *t, uint32 o, int flag)
{
Type *f;
- int32 w, m;
-
+ int32 w, maxalign;
+
+ maxalign = flag;
+ if(maxalign < 1)
+ maxalign = 1;
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
dowidth(f->type);
+ if(f->type->align > maxalign)
+ maxalign = f->type->align;
if(f->type->width < 0)
fatal("invalid width %lld", f->type->width);
w = f->type->width;
- m = arrayelemwidth(f->type);
- o = rnd(o, m);
+ o = rnd(o, f->type->align);
f->width = o; // really offset for TFIELD
if(f->nname != N) {
// this same stackparam logic is in addrescapes
@@ -82,7 +71,8 @@ widstruct(Type *t, uint32 o, int flag)
}
// final width is rounded
if(flag)
- o = rnd(o, maxround);
+ o = rnd(o, maxalign);
+ t->align = maxalign;
// type width only includes back to first field's offset
if(t->type == T)
@@ -100,7 +90,7 @@ dowidth(Type *t)
int lno;
Type *t1;
- if(maxround == 0 || widthptr == 0)
+ if(widthptr == 0)
fatal("dowidth without betypeinit");
if(t == T)
@@ -124,6 +114,7 @@ dowidth(Type *t)
lno = lineno;
lineno = t->lineno;
t->width = -2;
+ t->align = 0;
et = t->etype;
switch(et) {
@@ -166,9 +157,11 @@ dowidth(Type *t)
case TFLOAT64:
case TCOMPLEX64:
w = 8;
+ t->align = widthptr;
break;
case TCOMPLEX128:
w = 16;
+ t->align = widthptr;
break;
case TPTR32:
w = 4;
@@ -180,6 +173,7 @@ dowidth(Type *t)
break;
case TINTER: // implemented as 2 pointers
w = 2*widthptr;
+ t->align = widthptr;
offmod(t);
break;
case TCHAN: // implemented as pointer
@@ -197,6 +191,7 @@ dowidth(Type *t)
dowidth(t->type); // just in case
if(t1->type->width >= (1<<16))
yyerror("channel element type too large (>64kB)");
+ t->width = 1;
break;
case TMAP: // implemented as pointer
w = widthptr;
@@ -217,6 +212,7 @@ dowidth(Type *t)
if(sizeof_String == 0)
fatal("early dowidth string");
w = sizeof_String;
+ t->align = widthptr;
break;
case TARRAY:
if(t->type == T)
@@ -235,11 +231,13 @@ dowidth(Type *t)
yyerror("type %lT larger than address space", t);
w = t->bound * t->type->width;
if(w == 0)
- w = maxround;
+ w = 1;
+ t->align = t->type->align;
}
else if(t->bound == -1) {
w = sizeof_Array;
checkwidth(t->type);
+ t->align = widthptr;
}
else if(t->bound == -100)
yyerror("use of [...] array outside of array literal");
@@ -252,7 +250,9 @@ dowidth(Type *t)
fatal("dowidth fn struct %T", t);
w = widstruct(t, 0, 1);
if(w == 0)
- w = maxround;
+ w = 1;
+ //if(t->align < widthptr)
+ // warn("align %d: %T\n", t->align, t);
break;
case TFUNC:
@@ -271,16 +271,24 @@ dowidth(Type *t)
// compute their widths as side-effect.
t1 = t->type;
w = widstruct(*getthis(t1), 0, 0);
- w = widstruct(*getinarg(t1), w, 1);
- w = widstruct(*getoutarg(t1), w, 1);
+ w = widstruct(*getinarg(t1), w, widthptr);
+ w = widstruct(*getoutarg(t1), w, widthptr);
t1->argwid = w;
+ if(w%widthptr)
+ warn("bad type %T %d\n", t1, w);
+ t->align = 1;
break;
}
// catch all for error cases; avoid divide by zero later
if(w == 0)
- w = maxround;
+ w = 1;
t->width = w;
+ if(t->align == 0) {
+ if(w > 8 || (w&(w-1)) != 0)
+ fatal("invalid alignment for %T", t);
+ t->align = w;
+ }
lineno = lno;
if(defercalc == 1)
@@ -351,8 +359,8 @@ void
defercheckwidth(void)
{
// we get out of sync on syntax errors, so don't be pedantic.
- // if(defercalc)
- // fatal("defercheckwidth");
+ if(defercalc && nerrors == 0)
+ fatal("defercheckwidth");
defercalc = 1;
}
@@ -596,10 +604,10 @@ typeinit(void)
Array_array = rnd(0, widthptr);
Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width);
Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);
- sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround);
+ sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr);
// string is same as slice wo the cap
- sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround);
+ sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
dowidth(types[TSTRING]);
dowidth(idealstring);
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 3e2d98872..380abc642 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -1,6 +1,6 @@
char *runtimeimport =
"package runtime\n"
- "func \"\".mal (? int32) *any\n"
+ "func \"\".new (? int32) *any\n"
"func \"\".panicindex ()\n"
"func \"\".panicslice ()\n"
"func \"\".throwreturn ()\n"
@@ -19,12 +19,13 @@ char *runtimeimport =
"func \"\".printslice (? any)\n"
"func \"\".printnl ()\n"
"func \"\".printsp ()\n"
- "func \"\".printf ()\n"
- "func \"\".catstring (? string, ? string) string\n"
+ "func \"\".goprintf ()\n"
+ "func \"\".concatstring ()\n"
+ "func \"\".append ()\n"
+ "func \"\".appendslice (typ *uint8, x any, y []any) any\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
"func \"\".slicestring1 (? string, ? int) string\n"
- "func \"\".indexstring (? string, ? int) uint8\n"
"func \"\".intstring (? int64) string\n"
"func \"\".slicebytetostring (? []uint8) string\n"
"func \"\".sliceinttostring (? []int) string\n"
@@ -33,6 +34,7 @@ char *runtimeimport =
"func \"\".stringiter (? string, ? int) int\n"
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
"func \"\".slicecopy (to any, fr any, wid uint32) int\n"
+ "func \"\".slicestringcopy (to any, fr any) int\n"
"func \"\".convI2E (elem any) any\n"
"func \"\".convI2I (typ *uint8, elem any) any\n"
"func \"\".convT2E (typ *uint8, elem any) any\n"
@@ -75,16 +77,18 @@ char *runtimeimport =
"func \"\".selectdefault (sel *uint8) bool\n"
"func \"\".selectgo (sel *uint8)\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".sliceslice1 (old []any, lb int, width int) []any\n"
- "func \"\".sliceslice (old []any, lb int, hb int, width int) []any\n"
- "func \"\".slicearray (old *any, nel int, lb int, hb int, width int) []any\n"
+ "func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
+ "func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
+ "func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
"func \"\".closure ()\n"
"func \"\".int64div (? int64, ? int64) int64\n"
"func \"\".uint64div (? uint64, ? uint64) uint64\n"
"func \"\".int64mod (? int64, ? int64) int64\n"
"func \"\".uint64mod (? uint64, ? uint64) uint64\n"
"func \"\".float64toint64 (? float64) int64\n"
+ "func \"\".float64touint64 (? float64) uint64\n"
"func \"\".int64tofloat64 (? int64) float64\n"
+ "func \"\".uint64tofloat64 (? uint64) float64\n"
"func \"\".complex128div (num complex128, den complex128) complex128\n"
"\n"
"$$\n";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index a24a03a49..eb7014366 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -158,7 +158,7 @@ walkclosure(Node *func, NodeList **init)
// create the function
xfunc = nod(ODCLFUNC, N, N);
- snprint(namebuf, sizeof namebuf, "_func_%.3ld", ++closgen);
+ snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen);
xfunc->nname = newname(lookup(namebuf));
xfunc->nname->ntype = xtype;
xfunc->nname->defn = xfunc;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index cec95359a..72e67a634 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -101,7 +101,7 @@ convlit1(Node **np, Type *t, int explicit)
break;
case OLSH:
case ORSH:
- convlit1(&n->left, t, explicit);
+ convlit1(&n->left, t, explicit && isideal(n->left->type));
t = n->left->type;
if(t != T && !isint[t->etype]) {
yyerror("invalid operation: %#N (shift of type %T)", n, t);
@@ -202,8 +202,6 @@ convlit1(Node **np, Type *t, int explicit)
goto bad;
case CTFLT:
case CTINT:
- if(explicit)
- goto bad;
n->val = tocplx(n->val);
break;
case CTCPLX:
@@ -300,7 +298,7 @@ toflt(Val v)
f = mal(sizeof(*f));
mpmovefltflt(f, &v.u.cval->real);
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F truncated to real", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
v.ctype = CTFLT;
v.u.fval = f;
break;
@@ -324,9 +322,9 @@ toint(Val v)
case CTCPLX:
i = mal(sizeof(*i));
if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F truncated to integer", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F truncated to real", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
v.ctype = CTINT;
v.u.xval = i;
break;
@@ -536,6 +534,12 @@ evconst(Node *n)
v = toflt(v);
rv = toflt(rv);
}
+ if(v.ctype != rv.ctype) {
+ // Use of undefined name as constant?
+ if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
+ return;
+ fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
+ }
// run op
switch(TUP(n->op, v.ctype)) {
@@ -1086,6 +1090,12 @@ smallintconst(Node *n)
case TBOOL:
case TPTR32:
return 1;
+ case TINT64:
+ case TUINT64:
+ if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
+ || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
+ break;
+ return 1;
}
return 0;
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index adb1531c3..a71272aa2 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -729,8 +729,11 @@ stotype(NodeList *l, int et, Type **t)
n->right = N;
if(n->embedded && n->type != T) {
t1 = n->type;
- if(t1->sym == S && isptr[t1->etype])
+ if(t1->sym == S && isptr[t1->etype]) {
t1 = t1->type;
+ if(t1->etype == TINTER)
+ yyerror("embedded type cannot be a pointer to interface");
+ }
if(isptr[t1->etype])
yyerror("embedded type cannot be a pointer");
else if(t1->etype == TFORW && t1->embedlineno == 0)
@@ -841,6 +844,8 @@ dostruct(NodeList *l, int et)
t->broke = 1;
return t;
}
+ if(et == TINTER)
+ t = sortinter(t);
if(!funarg)
checkwidth(t);
return t;
@@ -1017,11 +1022,12 @@ functype(Node *this, NodeList *in, NodeList *out)
}
Sym*
-methodsym(Sym *nsym, Type *t0)
+methodsym(Sym *nsym, Type *t0, int iface)
{
Sym *s;
char *p;
Type *t;
+ char *suffix;
t = t0;
if(t == T)
@@ -1043,7 +1049,13 @@ methodsym(Sym *nsym, Type *t0)
if(t != t0 && t0->sym)
t0 = ptrto(t);
- p = smprint("%#hT·%s", t0, nsym->name);
+ suffix = "";
+ if(iface) {
+ dowidth(t0);
+ if(t0->width < types[tptr]->width)
+ suffix = "·i";
+ }
+ p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
s = pkglookup(p, s->pkg);
free(p);
return s;
@@ -1058,7 +1070,7 @@ methodname(Node *n, Type *t)
{
Sym *s;
- s = methodsym(n->sym, t);
+ s = methodsym(n->sym, t, 0);
if(s == S)
return n;
return newname(s);
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 108a091b2..21e1b103b 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -25,13 +25,18 @@ other packages. It is therefore not necessary when compiling client C of
package P to read the files of P's dependencies, only the compiled output
of P.
-Usage: 6g [flags] *.go (or 8g or 5g)
+Usage:
+ 6g [flags] file...
+The specified files must be Go source files and all part of the same package.
+Substitute 6g with 8g or 5g where appropriate.
Flags:
-o file
- output file, default 6.out for 6g, etc.
+ output file, default file.6 for 6g, etc.
-e
normally the compiler quits after 10 errors; -e prints all errors
+ -L
+ show entire file path when printing line numbers in errors
-I dir1 -I dir2
add dir1 and dir2 to the list of paths to check for imported packages
-N
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 52853c454..594509915 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -176,7 +176,8 @@ dumpexporttype(Sym *s)
yyerror("export of incomplete type %T", t);
return;
}
- Bprint(bout, "type %#T %l#T\n", t, t);
+ if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
+ fatal("Bprint failed for %T", t);
}
static int
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index fd8a7f39b..04af5a7bb 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -58,7 +58,7 @@ allocparams(void)
if(w >= MAXWIDTH)
fatal("bad width");
stksize += w;
- stksize = rnd(stksize, w);
+ stksize = rnd(stksize, n->type->align);
n->xoffset = -stksize;
}
lineno = lno;
@@ -139,8 +139,10 @@ gen(Node *n)
Prog *scontin, *sbreak;
Prog *p1, *p2, *p3;
Label *lab;
+ int32 wasregalloc;
lno = setlineno(n);
+ wasregalloc = anyregalloc();
if(n == N)
goto ret;
@@ -246,9 +248,6 @@ gen(Node *n)
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, breakpc); // if(!test) goto break
genlist(n->nbody); // body
gjmp(continpc);
@@ -261,9 +260,6 @@ gen(Node *n)
p1 = gjmp(P); // goto test
p2 = gjmp(P); // p2: goto else
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, p2); // if(!test) goto p2
genlist(n->nbody); // then
p3 = gjmp(P); // goto done
@@ -342,6 +338,11 @@ gen(Node *n)
}
ret:
+ if(anyregalloc() != wasregalloc) {
+ dump("node", n);
+ fatal("registers left allocated");
+ }
+
lineno = lno;
}
@@ -432,7 +433,7 @@ cgen_discard(Node *nr)
switch(nr->op) {
case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC)
+ if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
gused(nr);
break;
@@ -651,7 +652,6 @@ tempname(Node *n, Type *t)
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
-
memset(n, 0, sizeof(*n));
n->op = ONAME;
n->sym = s;
@@ -664,7 +664,7 @@ tempname(Node *n, Type *t)
dowidth(t);
w = t->width;
stksize += w;
- stksize = rnd(stksize, w);
+ stksize = rnd(stksize, t->align);
n->xoffset = -stksize;
n->pun = anyregalloc();
}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
index cdd7578d4..b5af4678c 100644
--- a/src/cmd/gc/go.errors
+++ b/src/cmd/gc/go.errors
@@ -35,6 +35,15 @@ static struct {
% loadsys package imports LTYPE LNAME ';'
"unexpected semicolon or newline in type declaration",
+ % loadsys package imports LCHAN '}'
+ "unexpected } in channel type",
+
+ % loadsys package imports LCHAN ')'
+ "unexpected ) in channel type",
+
+ % loadsys package imports LCHAN ','
+ "unexpected comma in channel type",
+
% loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
"unexpected semicolon or newline before else",
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 99e369eca..73ea5b976 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -6,6 +6,8 @@
#include <libc.h>
#include <bio.h>
+#undef OAPPEND
+
// avoid <ctype.h>
#undef isblank
#define isblank goisblank
@@ -38,9 +40,10 @@ enum
ASTRING,
AINTER,
ANILINTER,
+ AMEMWORD,
BADWIDTH = -1000000000,
- MAXWIDTH = 1<<30
+ MAXWIDTH = 1<<30
};
/*
@@ -151,6 +154,7 @@ struct Type
uchar deferwidth;
uchar broke;
uchar isddd; // TFIELD is ... argument
+ uchar align;
Node* nod; // canonical OTYPE node
Type* orig; // original type (type literal or predefined type)
@@ -209,12 +213,15 @@ struct Node
uchar dodata; // compile literal assignment as data statement
uchar used;
uchar isddd;
- uchar pun; // dont registerize variable ONAME
+ uchar pun; // don't registerize variable ONAME
+ uchar readonly;
+ uchar implicit; // don't show in printout
// most nodes
Node* left;
Node* right;
Type* type;
+ Type* realtype; // as determined by typecheck
NodeList* list;
NodeList* rlist;
@@ -261,6 +268,7 @@ struct Node
Sym* sym; // various
int32 vargen; // unique name for OTYPE/ONAME
int32 lineno;
+ int32 endlineno;
vlong xoffset;
int32 ostk;
int32 iota;
@@ -344,6 +352,7 @@ enum
OADD, OSUB, OOR, OXOR, OADDSTR,
OADDR,
OANDAND,
+ OAPPEND,
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
@@ -356,7 +365,7 @@ enum
OCLOSURE,
OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
- OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE,
+ OCONV, OCONVIFACE, OCONVNOP,
OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
@@ -364,7 +373,7 @@ enum
ODOTTYPE2,
OEQ, ONE, OLT, OLE, OGE, OGT,
OIND,
- OINDEX, OINDEXSTR, OINDEXMAP,
+ OINDEX, OINDEXMAP,
OKEY, OPARAM,
OLEN,
OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
@@ -400,7 +409,6 @@ enum
ORETURN,
OSELECT,
OSWITCH,
- OTYPECASE,
OTYPESW, // l = r.(type)
// types
@@ -410,6 +418,7 @@ enum
OTINTER,
OTFUNC,
OTARRAY,
+ OTPAREN,
// misc
ODDD,
@@ -632,9 +641,9 @@ EXTERN Label* labellist;
*
* typedef struct
* { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * uchar cap[4]; // allocated number of elements
+ * uchar array[8]; // pointer to data
+ * uchar nel[4]; // number of elements
+ * uchar cap[4]; // allocated number of elements
* } Array;
*/
EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
@@ -649,8 +658,8 @@ EXTERN int sizeof_Array; // runtime sizeof(Array)
*
* typedef struct
* { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
+ * uchar array[8]; // pointer to data
+ * uchar nel[4]; // number of elements
* } String;
*/
EXTERN int sizeof_String; // runtime sizeof(String)
@@ -743,7 +752,6 @@ EXTERN int hasdefer; // flag that curfn has defer statetment
EXTERN Node* curfn;
-EXTERN int maxround;
EXTERN int widthptr;
EXTERN Node* typesw;
@@ -858,7 +866,7 @@ int isifacemethod(Type *f);
void markdcl(void);
Node* methodname(Node *n, Type *t);
Node* methodname1(Node *n, Node *t);
-Sym* methodsym(Sym *nsym, Type *t0);
+Sym* methodsym(Sym *nsym, Type *t0, int iface);
Node* newname(Sym *s);
Type* newtype(Sym *s);
Node* oldname(Sym *s);
@@ -914,6 +922,9 @@ char* lexname(int lex);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);
+extern int windows;
+extern int yylast;
+extern int yyprev;
/*
* mparith1.c
@@ -1003,7 +1014,7 @@ void walkrange(Node *n);
* reflect.c
*/
void dumptypestructs(void);
-Type* methodfunc(Type *f, int use_receiver);
+Type* methodfunc(Type *f, Type*);
Node* typename(Type *t);
Sym* typesym(Type *t);
@@ -1016,7 +1027,7 @@ void walkselect(Node *sel);
/*
* sinit.c
*/
-void anylit(int ctxt, Node *n, Node *var, NodeList **init);
+void anylit(int, Node *n, Node *var, NodeList **init);
int gen_as_init(Node *n);
NodeList* initfix(NodeList *l);
int oaslit(Node *n, NodeList **init);
@@ -1059,7 +1070,7 @@ void flusherrors(void);
void frame(int context);
Type* funcfirst(Iter *s, Type *t);
Type* funcnext(Iter *s);
-void genwrapper(Type *rcvr, Type *method, Sym *newnam);
+void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
Type** getinarg(Type *t);
Type* getinargx(Type *t);
Type** getoutarg(Type *t);
@@ -1095,6 +1106,7 @@ Node* nod(int op, Node *nleft, Node *nright);
Node* nodbool(int b);
void nodconst(Node *n, Type *t, int64 v);
Node* nodintconst(int64 v);
+Node* nodfltconst(Mpflt *v);
Node* nodnil(void);
int parserline(void);
Sym* pkglookup(char *name, Pkg *pkg);
@@ -1103,13 +1115,13 @@ Type* ptrto(Type *t);
void* remal(void *p, int32 on, int32 n);
Sym* restrictlookup(char *name, Pkg *pkg);
Node* safeexpr(Node *n, NodeList **init);
+Node* cheapexpr(Node *n, NodeList **init);
int32 setlineno(Node *n);
void setmaxarg(Type *t);
Type* shallow(Type *t);
int simsimtype(Type *t);
void smagic(Magic *m);
Type* sortinter(Type *t);
-Node* staticname(Type *t);
uint32 stringhash(char *p);
Strlit* strlit(char *s);
int structcount(Type *t);
@@ -1143,7 +1155,7 @@ void typechecklist(NodeList *l, int top);
/*
* unsafe.c
*/
-Node* unsafenmagic(Node *fn, NodeList *args);
+Node* unsafenmagic(Node *n);
/*
* walk.c
@@ -1206,7 +1218,7 @@ void dumpfuncs(void);
void gdata(Node*, Node*, int);
void gdatacomplex(Node*, Mpcplx*);
void gdatastring(Node*, Strlit*);
-void genembedtramp(Type*, Type*, Sym*);
+void genembedtramp(Type*, Type*, Sym*, int iface);
void ggloblnod(Node *nam, int32 width);
void ggloblsym(Sym *s, int32 width, int dupok);
Prog* gjmp(Prog*);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index c46abaa56..917265758 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -20,6 +20,8 @@
%{
#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
#include "go.h"
+
+static void fixlbrace(int);
%}
%union {
Node* node;
@@ -50,7 +52,7 @@
%type <node> stmt ntype
%type <node> arg_type
%type <node> case caseblock
-%type <node> compound_stmt dotname embed expr
+%type <node> compound_stmt dotname embed expr complitexpr
%type <node> expr_or_type
%type <node> fndcl fnliteral
%type <node> for_body for_header for_stmt if_header if_stmt non_dcl_stmt
@@ -58,7 +60,7 @@
%type <node> name_or_type non_expr_type
%type <node> new_name dcl_name oexpr typedclname
%type <node> onew_name
-%type <node> osimple_stmt pexpr
+%type <node> osimple_stmt pexpr pexpr_no_paren
%type <node> pseudocall range_stmt select_stmt
%type <node> simple_stmt
%type <node> switch_stmt uexpr
@@ -66,7 +68,7 @@
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type <list> oexpr_list oexpr_or_type_list_ocomma caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
+%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
@@ -459,7 +461,7 @@ case:
}
break;
}
-| LCASE name '=' expr ':'
+| LCASE expr '=' expr ':'
{
// will be converted to OCASE
// right will point to next case
@@ -515,10 +517,33 @@ switch_body:
}
caseblock:
- case stmt_list
+ case
+ {
+ // If the last token read by the lexer was consumed
+ // as part of the case, clear it (parser has cleared yychar).
+ // If the last token read by the lexer was the lookahead
+ // leave it alone (parser has it cached in yychar).
+ // This is so that the stmt_list action doesn't look at
+ // the case tokens if the stmt_list is empty.
+ yylast = yychar;
+ }
+ stmt_list
{
+ int last;
+
+ // This is the only place in the language where a statement
+ // list is not allowed to drop the final semicolon, because
+ // it's the only place where a statement list is not followed
+ // by a closing brace. Handle the error for pedantry.
+
+ // Find the final token of the statement list.
+ // yylast is lookahead; yyprev is last of stmt_list
+ last = yyprev;
+
+ if(last > 0 && last != ';' && yychar != '}')
+ yyerror("missing statement after label");
$$ = $1;
- $$->nbody = $2;
+ $$->nbody = $3;
}
caseblock_list:
@@ -648,11 +673,13 @@ select_stmt:
LSELECT
{
markdcl();
+ typesw = nod(OXXX, typesw, N);
}
switch_body
{
$$ = nod(OSELECT, N, N);
$$->list = $3;
+ typesw = typesw->left;
popdcl();
}
@@ -783,13 +810,23 @@ uexpr:
* can be preceded by 'defer' and 'go'
*/
pseudocall:
- pexpr '(' oexpr_or_type_list_ocomma ')'
+ pexpr '(' ')'
+ {
+ $$ = nod(OCALL, $1, N);
+ }
+| pexpr '(' expr_or_type_list ocomma ')'
{
$$ = nod(OCALL, $1, N);
$$->list = $3;
}
+| pexpr '(' expr_or_type_list LDDD ocomma ')'
+ {
+ $$ = nod(OCALL, $1, N);
+ $$->list = $3;
+ $$->isddd = 1;
+ }
-pexpr:
+pexpr_no_paren:
LLITERAL
{
$$ = nodlit($1);
@@ -806,10 +843,6 @@ pexpr:
}
$$ = nod(OXDOT, $1, newname($3));
}
-| '(' expr_or_type ')'
- {
- $$ = $2;
- }
| pexpr '.' '(' expr_or_type ')'
{
$$ = nod(ODOTTYPE, $1, $4);
@@ -824,10 +857,6 @@ pexpr:
}
| pexpr '[' oexpr ':' oexpr ']'
{
- if($3 == N) {
- yyerror("missing lower bound in slice expression");
- $3 = nodintconst(0);
- }
$$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
}
| pseudocall
@@ -842,21 +871,45 @@ pexpr:
// composite expression
$$ = nod(OCOMPLIT, N, $1);
$$->list = $3;
-
- // If the opening brace was an LBODY,
- // set up for another one now that we're done.
- // See comment in lex.c about loophack.
- if($2 == LBODY)
- loophack = 1;
+
+ fixlbrace($2);
}
-| pexpr '{' braced_keyval_list '}'
+| pexpr_no_paren '{' braced_keyval_list '}'
{
// composite expression
$$ = nod(OCOMPLIT, N, $1);
$$->list = $3;
}
+| '(' expr_or_type ')' '{' braced_keyval_list '}'
+ {
+ yyerror("cannot parenthesize type in composite literal");
+ // composite expression
+ $$ = nod(OCOMPLIT, N, $2);
+ $$->list = $5;
+ }
| fnliteral
+keyval:
+ expr ':' complitexpr
+ {
+ $$ = nod(OKEY, $1, $3);
+ }
+
+complitexpr:
+ expr
+| '{' braced_keyval_list '}'
+ {
+ $$ = nod(OCOMPLIT, N, N);
+ $$->list = $2;
+ }
+
+pexpr:
+ pexpr_no_paren
+| '(' expr_or_type ')'
+ {
+ $$ = $2;
+ }
+
expr_or_type:
expr
| non_expr_type %prec PreferToRightParen
@@ -939,7 +992,7 @@ ntype:
| dotname
| '(' ntype ')'
{
- $$ = $2;
+ $$ = nod(OTPAREN, $2, N);
}
non_expr_type:
@@ -958,7 +1011,7 @@ non_recvchantype:
| dotname
| '(' ntype ')'
{
- $$ = $2;
+ $$ = nod(OTPAREN, $2, N);
}
convtype:
@@ -1030,34 +1083,31 @@ recvchantype:
}
structtype:
- LSTRUCT '{' structdcl_list osemi '}'
+ LSTRUCT lbrace structdcl_list osemi '}'
{
$$ = nod(OTSTRUCT, N, N);
$$->list = $3;
+ fixlbrace($2);
}
-| LSTRUCT '{' '}'
+| LSTRUCT lbrace '}'
{
$$ = nod(OTSTRUCT, N, N);
+ fixlbrace($2);
}
interfacetype:
- LINTERFACE '{' interfacedcl_list osemi '}'
+ LINTERFACE lbrace interfacedcl_list osemi '}'
{
$$ = nod(OTINTER, N, N);
$$->list = $3;
+ fixlbrace($2);
}
-| LINTERFACE '{' '}'
+| LINTERFACE lbrace '}'
{
$$ = nod(OTINTER, N, N);
+ fixlbrace($2);
}
-keyval:
- expr ':' expr
- {
- $$ = nod(OKEY, $1, $3);
- }
-
-
/*
* function stuff
* all in one place to show how crappy it all is
@@ -1069,6 +1119,7 @@ xfndcl:
if($$ == N)
break;
$$->nbody = $3;
+ $$->endlineno = lineno;
funcbody($$);
}
@@ -1118,6 +1169,8 @@ fndcl:
yyerror("bad receiver in method");
break;
}
+ if(rcvr->right->op == OTPAREN || (rcvr->right->op == OIND && rcvr->right->left->op == OTPAREN))
+ yyerror("cannot parenthesize receiver type");
$$ = nod(ODCLFUNC, N, N);
$$->nname = methodname1(name, rcvr->right);
@@ -1250,12 +1303,32 @@ structdcl:
$1->val = $2;
$$ = list1($1);
}
+| '(' embed ')' oliteral
+ {
+ $2->val = $4;
+ $$ = list1($2);
+ yyerror("cannot parenthesize embedded type");
+ }
| '*' embed oliteral
{
$2->right = nod(OIND, $2->right, N);
$2->val = $3;
$$ = list1($2);
}
+| '(' '*' embed ')' oliteral
+ {
+ $3->right = nod(OIND, $3->right, N);
+ $3->val = $5;
+ $$ = list1($3);
+ yyerror("cannot parenthesize embedded type");
+ }
+| '*' '(' embed ')' oliteral
+ {
+ $3->right = nod(OIND, $3->right, N);
+ $3->val = $5;
+ $$ = list1($3);
+ yyerror("cannot parenthesize embedded type");
+ }
packname:
LNAME
@@ -1296,6 +1369,11 @@ interfacedcl:
{
$$ = nod(ODCLFIELD, N, oldname($1));
}
+| '(' packname ')'
+ {
+ $$ = nod(ODCLFIELD, N, oldname($2));
+ yyerror("cannot parenthesize embedded type");
+ }
indcl:
'(' oarg_type_list_ocomma ')' fnres
@@ -1481,7 +1559,7 @@ keyval_list:
{
$$ = list1($1);
}
-| expr
+| complitexpr
{
$$ = list1($1);
}
@@ -1489,7 +1567,7 @@ keyval_list:
{
$$ = list($1, $3);
}
-| keyval_list ',' expr
+| keyval_list ',' complitexpr
{
$$ = list($1, $3);
}
@@ -1524,12 +1602,6 @@ oexpr_list:
}
| expr_list
-oexpr_or_type_list_ocomma:
- {
- $$ = nil;
- }
-| expr_or_type_list ocomma
-
osimple_stmt:
{
$$ = N;
@@ -1654,7 +1726,6 @@ hidden_type_misc:
| LINTERFACE '{' ohidden_interfacedcl_list '}'
{
$$ = dostruct($3, TINTER);
- $$ = sortinter($$);
}
| '*' hidden_type
{
@@ -1867,3 +1938,16 @@ hidden_interfacedcl_list:
{
$$ = list($1, $3);
}
+
+%%
+
+static void
+fixlbrace(int lbr)
+{
+ // If the opening brace was an LBODY,
+ // set up for another one now that we're done.
+ // See comment in lex.c about loophack.
+ if(lbr == LBODY)
+ loophack = 1;
+}
+
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 452acfc76..0f1acd2fc 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -14,6 +14,8 @@
extern int yychar;
int windows;
+int yyprev;
+int yylast;
static void lexinit(void);
static void lexfini(void);
@@ -23,9 +25,45 @@ static void ungetc(int);
static int32 getr(void);
static int escchar(int, int*, vlong*);
static void addidir(char*);
-
+static int getlinepragma(void);
static char *goos, *goarch, *goroot;
+// Our own isdigit, isspace, isalpha, isalnum that take care
+// of EOF and other out of range arguments.
+static int
+yy_isdigit(int c)
+{
+ return c >= 0 && c <= 0xFF && isdigit(c);
+}
+
+static int
+yy_isspace(int c)
+{
+ return c >= 0 && c <= 0xFF && isspace(c);
+}
+
+static int
+yy_isalpha(int c)
+{
+ return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+static int
+yy_isalnum(int c)
+{
+ return c >= 0 && c <= 0xFF && isalnum(c);
+}
+
+// Disallow use of isdigit etc.
+#undef isdigit
+#undef isspace
+#undef isalpha
+#undef isalnum
+#define isdigit use_yy_isdigit_instead_of_isdigit
+#define isspace use_yy_isspace_instead_of_isspace
+#define isalpha use_yy_isalpha_instead_of_isalpha
+#define isalnum use_yy_isalnum_instead_of_isalnum
+
#define DBG if(!debug['x']);else print
enum
{
@@ -35,7 +73,7 @@ enum
void
usage(void)
{
- print("usage: %cg [flags] file.go...\n");
+ print("gc: usage: %cg [flags] file.go...\n", thechar);
print("flags:\n");
// -A is allow use of "any" type, for bootstrapping
print(" -I DIR search for packages in DIR\n");
@@ -52,12 +90,27 @@ usage(void)
exit(0);
}
+void
+fault(int s)
+{
+ // If we've already complained about things
+ // in the program, don't bother complaining
+ // about the seg fault too; let the user clean up
+ // the code and try again.
+ if(nerrors > 0)
+ errorexit();
+ fatal("fault");
+}
+
int
main(int argc, char *argv[])
{
int i, c;
NodeList *l;
char *p;
+
+ signal(SIGBUS, fault);
+ signal(SIGSEGV, fault);
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
@@ -119,7 +172,7 @@ main(int argc, char *argv[])
if(getwd(pathname, 999) == 0)
strcpy(pathname, "/???");
- if(isalpha(pathname[0]) && pathname[1] == ':') {
+ if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
// On Windows.
windows = 1;
@@ -141,7 +194,7 @@ main(int argc, char *argv[])
fmtinstall('F', Fconv); // big float numbers
betypeinit();
- if(maxround == 0 || widthptr == 0)
+ if(widthptr == 0)
fatal("betypeinit failed");
lexinit();
@@ -287,7 +340,7 @@ islocalname(Strlit *name)
if(!windows && name->len >= 1 && name->s[0] == '/')
return 1;
if(windows && name->len >= 3 &&
- isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
+ yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
return 1;
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
return 1;
@@ -300,8 +353,11 @@ static int
findpkg(Strlit *name)
{
Idir *p;
+ char *q;
if(islocalname(name)) {
+ if(safemode)
+ return 0;
// try .a before .6. important for building libraries:
// if there is an array.6 in the array.a library,
// want to find all of array.a, not just array.6.
@@ -314,6 +370,18 @@ findpkg(Strlit *name)
return 0;
}
+ // local imports should be canonicalized already.
+ // don't want to see "container/../container/vector"
+ // as different from "container/vector".
+ q = mal(name->len+1);
+ memmove(q, name->s, name->len);
+ q[name->len] = '\0';
+ cleanname(q);
+ if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
+ yyerror("non-canonical import path %Z (should be %s)", name, q);
+ return 0;
+ }
+
for(p = idirs; p != nil; p = p->link) {
snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
if(access(namebuf, 0) >= 0)
@@ -368,7 +436,9 @@ importfile(Val *f, int line)
path = f->u.sval;
if(islocalname(path)) {
cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
- sprint(cleanbuf, "%s/%s", pathname, path->s);
+ strcpy(cleanbuf, pathname);
+ strcat(cleanbuf, "/");
+ strcat(cleanbuf, path->s);
cleanname(cleanbuf);
path = strlit(cleanbuf);
}
@@ -381,7 +451,7 @@ importfile(Val *f, int line)
imp = Bopen(namebuf, OREAD);
if(imp == nil) {
- yyerror("can't open import: %Z", f->u.sval);
+ yyerror("can't open import: %Z: %r", f->u.sval);
errorexit();
}
file = strdup(namebuf);
@@ -470,7 +540,7 @@ isfrog(int c)
return 0;
return 1;
}
- if(0x80 <= c && c <= 0xa0) // unicode block including unbreakable space.
+ if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
return 1;
return 0;
}
@@ -496,7 +566,7 @@ _yylex(void)
l0:
c = getc();
- if(isspace(c)) {
+ if(yy_isspace(c)) {
if(c == '\n' && curio.nlsemi) {
ungetc(c);
DBG("lex: implicit semi\n");
@@ -514,13 +584,13 @@ l0:
goto talph;
}
- if(isalpha(c)) {
+ if(yy_isalpha(c)) {
cp = lexbuf;
ep = lexbuf+sizeof lexbuf;
goto talph;
}
- if(isdigit(c))
+ if(yy_isdigit(c))
goto tnum;
switch(c) {
@@ -536,7 +606,7 @@ l0:
case '.':
c1 = getc();
- if(isdigit(c1)) {
+ if(yy_isdigit(c1)) {
cp = lexbuf;
ep = lexbuf+sizeof lexbuf;
*cp++ = c;
@@ -656,16 +726,13 @@ l0:
}
}
if(c1 == '/') {
+ c = getlinepragma();
for(;;) {
- c = getr();
- if(c == '\n') {
+ if(c == '\n' || c == EOF) {
ungetc(c);
goto l0;
}
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
+ c = getr();
}
}
if(c1 == '=') {
@@ -878,6 +945,10 @@ lx:
yyerror("illegal character 0x%ux", c);
goto l0;
}
+ if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
+ yyerror("%s: unexpected %c", "syntax error", c);
+ goto l0;
+ }
return c;
asop:
@@ -902,7 +973,7 @@ talph:
if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
yyerror("invalid identifier character 0x%ux", rune);
cp += runetochar(cp, &rune);
- } else if(!isalnum(c) && c != '_')
+ } else if(!yy_isalnum(c) && c != '_')
break;
else
*cp++ = c;
@@ -940,7 +1011,7 @@ tnum:
}
*cp++ = c;
c = getc();
- if(isdigit(c))
+ if(yy_isdigit(c))
continue;
goto dc;
}
@@ -955,7 +1026,7 @@ tnum:
}
*cp++ = c;
c = getc();
- if(isdigit(c))
+ if(yy_isdigit(c))
continue;
if(c >= 'a' && c <= 'f')
continue;
@@ -976,7 +1047,7 @@ tnum:
yyerror("identifier too long");
errorexit();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
break;
if(c < '0' || c > '7')
c1 = 1; // not octal
@@ -1025,7 +1096,7 @@ casedot:
}
*cp++ = c;
c = getc();
- if(!isdigit(c))
+ if(!yy_isdigit(c))
break;
}
if(c == 'i')
@@ -1040,9 +1111,9 @@ casee:
*cp++ = c;
c = getc();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
yyerror("malformed fp constant exponent");
- while(isdigit(c)) {
+ while(yy_isdigit(c)) {
if(cp+10 >= ep) {
yyerror("identifier too long");
errorexit();
@@ -1061,9 +1132,9 @@ casep:
*cp++ = c;
c = getc();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
yyerror("malformed fp constant exponent");
- while(isdigit(c)) {
+ while(yy_isdigit(c)) {
if(cp+10 >= ep) {
yyerror("identifier too long");
errorexit();
@@ -1104,6 +1175,68 @@ caseout:
return LLITERAL;
}
+/*
+ * read and interpret syntax that looks like
+ * //line parse.y:15
+ * as a discontinuity in sequential line numbers.
+ * the next line of input comes from parse.y:15
+ */
+static int
+getlinepragma(void)
+{
+ int i, c, n;
+ char *cp, *ep;
+ Hist *h;
+
+ for(i=0; i<5; i++) {
+ c = getr();
+ if(c != "line "[i])
+ goto out;
+ }
+
+ cp = lexbuf;
+ ep = lexbuf+sizeof(lexbuf)-5;
+ for(;;) {
+ c = getr();
+ if(c == '\n' || c == EOF)
+ goto out;
+ if(c == ' ')
+ continue;
+ if(c == ':')
+ break;
+ if(cp < ep)
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ n = 0;
+ for(;;) {
+ c = getr();
+ if(!yy_isdigit(c))
+ break;
+ n = n*10 + (c-'0');
+ if(n > 1e8) {
+ yyerror("line number out of range");
+ errorexit();
+ }
+ }
+
+ if(c != '\n' || n <= 0)
+ goto out;
+
+ // try to avoid allocating file name over and over
+ for(h=hist; h!=H; h=h->link) {
+ if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
+ linehist(h->name, n, 0);
+ goto out;
+ }
+ }
+ linehist(strdup(lexbuf), n, 0);
+
+out:
+ return c;
+}
+
int32
yylex(void)
{
@@ -1112,13 +1245,8 @@ yylex(void)
lx = _yylex();
if(curio.nlsemi && lx == EOF) {
- // if the nlsemi bit is set, we'd be willing to
- // insert a ; if we saw a \n, but we didn't.
- // that means the final \n is missing.
- // complain here, because we can give a
- // good message. the syntax error we'd get
- // otherwise is inscrutable.
- yyerror("missing newline at end of file");
+ // Treat EOF as "end of line" for the purposes
+ // of inserting a semicolon.
lx = ';';
}
@@ -1140,7 +1268,11 @@ yylex(void)
curio.nlsemi = 0;
break;
}
- return lx;
+
+ // Track last two tokens returned by yylex.
+ yyprev = yylast;
+ yylast = lx;
+ return lx;
}
static int
@@ -1395,6 +1527,7 @@ static struct
"type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX,
+ "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
index 13309ec32..4dfff1caa 100755
--- a/src/cmd/gc/mkbuiltin
+++ b/src/cmd/gc/mkbuiltin
@@ -10,11 +10,9 @@
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
if [ -z "$GC" ]; then
- echo 'missing $GC - maybe no Make.$GOARCH?' 1>&2
+ echo 'missing $GC - gomake failed?' 1>&2
exit 1
fi
@@ -22,7 +20,7 @@ gcc -o mkbuiltin1 mkbuiltin1.c
rm -f _builtin.c
for i in runtime unsafe
do
- "$GOBIN"/$GC -A $i.go
+ $GC -A $i.go
O=$O ./mkbuiltin1 $i >>_builtin.c
done
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index 8110e77b9..6cd4e2500 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -156,10 +156,11 @@ mpmovefixflt(Mpflt *a, Mpint *b)
// convert (truncate) b to a.
// return -1 (but still convert) if b was non-integer.
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
+static int
+mpexactfltfix(Mpint *a, Mpflt *b)
{
Mpflt f;
+
*a = b->val;
mpshiftfix(a, b->exp);
if(b->exp < 0) {
@@ -172,6 +173,35 @@ mpmovefltfix(Mpint *a, Mpflt *b)
return 0;
}
+int
+mpmovefltfix(Mpint *a, Mpflt *b)
+{
+ Mpflt f;
+ int i;
+
+ if(mpexactfltfix(a, b) == 0)
+ return 0;
+
+ // try rounding down a little
+ f = *b;
+ f.val.a[0] = 0;
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ // try rounding up a little
+ for(i=1; i<Mpprec; i++) {
+ f.val.a[i]++;
+ if(f.val.a[i] != Mpbase)
+ break;
+ f.val.a[i] = 0;
+ }
+ mpnorm(&f);
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ return -1;
+}
+
void
mpmovefixfix(Mpint *a, Mpint *b)
{
@@ -188,6 +218,8 @@ static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
static void
mppow10flt(Mpflt *a, int p)
{
+ if(p < 0)
+ abort();
if(p < nelem(tab)) {
mpmovecflt(a, tab[p]);
return;
@@ -267,6 +299,10 @@ mpatoflt(Mpflt *a, char *as)
}
if(c >= '0' && c <= '9') {
ex = ex*10 + (c-'0');
+ if(ex > 1e8) {
+ yyerror("exponent out of range");
+ errorexit();
+ }
continue;
}
break;
@@ -439,6 +475,8 @@ Fconv(Fmt *fp)
// for well in range, convert to double and use print's %g
if(-900 < fvp->exp && fvp->exp < 900) {
d = mpgetflt(fvp);
+ if(d >= 0 && (fp->flags & FmtSign))
+ fmtprint(fp, "+");
return fmtprint(fp, "%g", d);
}
// TODO(rsc): for well out of range, print
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index b025917fa..403255005 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -319,7 +319,11 @@ mpmulfract(Mpint *a, Mpint *b)
s.neg = 0;
mpmovecfix(&q, 0);
- for(i=0; i<Mpprec; i++) {
+ x = *--a1;
+ if(x != 0)
+ yyerror("mpmulfract not normal");
+
+ for(i=0; i<Mpprec-1; i++) {
x = *--a1;
if(x == 0) {
mprshw(&s);
@@ -532,7 +536,7 @@ mpgetfix(Mpint *a)
vlong v;
if(a->ovf) {
- yyerror("ovf in mpgetfix");
+ yyerror("constant overflow");
return 0;
}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index b9cd4ea84..7b7e66668 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -27,16 +27,36 @@ sigfig(Mpflt *a)
void
mpnorm(Mpflt *a)
{
- int s;
+ int s, os;
+ long x;
- s = sigfig(a);
- if(s == 0) {
+ os = sigfig(a);
+ if(os == 0) {
// zero
a->exp = 0;
a->val.neg = 0;
return;
}
- s = (Mpnorm-s) * Mpscale;
+
+ // this will normalize to the nearest word
+ x = a->val.a[os-1];
+ s = (Mpnorm-os) * Mpscale;
+
+ // further normalize to the nearest bit
+ for(;;) {
+ x <<= 1;
+ if(x & Mpbase)
+ break;
+ s++;
+ if(x == 0) {
+ // this error comes from trying to
+ // convert an Inf or something
+ // where the initial x=0x80000000
+ s = (Mpnorm-os) * Mpscale;
+ break;
+ }
+ }
+
mpshiftfix(&a->val, s);
a->exp -= s;
}
@@ -109,7 +129,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b)
}
mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - 1;
+ a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
mpnorm(a);
if(Mpdebug)
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index ae16f2725..0d0d70ac9 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -74,41 +74,96 @@ Bputname(Biobuf *b, Sym *s)
}
static void
+outzfile(Biobuf *b, char *p)
+{
+ char *q, *q2;
+
+ while(p) {
+ q = utfrune(p, '/');
+ if(windows) {
+ q2 = utfrune(p, '\\');
+ if(q2 && (!q || q2 < q))
+ q = q2;
+ }
+ if(!q) {
+ zfile(b, p, strlen(p));
+ return;
+ }
+ if(q > p)
+ zfile(b, p, q-p);
+ p = q + 1;
+ }
+}
+
+#define isdelim(c) (c == '/' || c == '\\')
+
+static void
+outwinname(Biobuf *b, Hist *h, char *ds, char *p)
+{
+ if(isdelim(p[0])) {
+ // full rooted name
+ zfile(b, ds, 3); // leading "c:/"
+ outzfile(b, p+1);
+ } else {
+ // relative name
+ if(h->offset == 0 && pathname && pathname[1] == ':') {
+ if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
+ // using current drive
+ zfile(b, pathname, 3); // leading "c:/"
+ outzfile(b, pathname+3);
+ } else {
+ // using drive other then current,
+ // we don't have any simple way to
+ // determine current working directory
+ // there, therefore will output name as is
+ zfile(b, ds, 2); // leading "c:"
+ }
+ }
+ outzfile(b, p);
+ }
+}
+
+static void
outhist(Biobuf *b)
{
Hist *h;
- char *p, *q, *op;
- int n;
+ char *p, ds[] = {'c', ':', '/', 0};
for(h = hist; h != H; h = h->link) {
p = h->name;
- op = 0;
-
- if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') {
- op = p;
- p = pathname;
- }
-
- while(p) {
- q = utfrune(p, '/');
- if(q) {
- n = q-p;
- if(n == 0)
- n = 1; // leading "/"
- q++;
+ if(p) {
+ if(windows) {
+ // if windows variable is set, then, we know already,
+ // pathname is started with windows drive specifier
+ // and all '\' were replaced with '/' (see lex.c)
+ if(isdelim(p[0]) && isdelim(p[1])) {
+ // file name has network name in it,
+ // like \\server\share\dir\file.go
+ zfile(b, "//", 2); // leading "//"
+ outzfile(b, p+2);
+ } else if(p[1] == ':') {
+ // file name has drive letter in it
+ ds[0] = p[0];
+ outwinname(b, h, ds, p+2);
+ } else {
+ // no drive letter in file name
+ outwinname(b, h, pathname, p);
+ }
} else {
- n = strlen(p);
- q = 0;
- }
- if(n)
- zfile(b, p, n);
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
+ if(p[0] == '/') {
+ // full rooted name, like /home/rsc/dir/file.go
+ zfile(b, "/", 1); // leading "/"
+ outzfile(b, p+1);
+ } else {
+ // relative name, like dir/file.go
+ if(h->offset == 0 && pathname && pathname[0] == '/') {
+ zfile(b, "/", 1); // leading "/"
+ outzfile(b, pathname+1);
+ }
+ outzfile(b, p);
+ }
}
}
-
zhist(b, h->line, h->offset);
}
}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index 8738eb41b..6bb1f026b 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -23,14 +23,21 @@ void
exprfmt(Fmt *f, Node *n, int prec)
{
int nprec;
+ char *p;
nprec = 0;
if(n == nil) {
fmtprint(f, "<nil>");
return;
}
+
+ if(n->implicit) {
+ exprfmt(f, n->left, prec);
+ return;
+ }
switch(n->op) {
+ case OAPPEND:
case ONAME:
case ONONAME:
case OPACK:
@@ -53,9 +60,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case OPRINT:
case OPRINTN:
case OCALL:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
case OCONV:
case OCONVNOP:
- case OCONVSLICE:
case OMAKESLICE:
case ORUNESTR:
case OADDR:
@@ -66,6 +75,9 @@ exprfmt(Fmt *f, Node *n, int prec)
case OPLUS:
case ORECV:
case OCONVIFACE:
+ case OTPAREN:
+ case OINDEX:
+ case OINDEXMAP:
nprec = 7;
break;
@@ -106,6 +118,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case OOROR:
nprec = 1;
break;
+
+ case OTYPE:
+ if(n->sym != S)
+ nprec = 7;
+ break;
}
if(prec > nprec)
@@ -118,6 +135,10 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OLITERAL:
+ if(n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
switch(n->val.ctype) {
default:
goto bad;
@@ -154,6 +175,10 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OTYPE:
+ if(n->type == T && n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
fmtprint(f, "%T", n->type);
break;
@@ -161,6 +186,12 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "[]");
exprfmt(f, n->left, PFIXME);
break;
+
+ case OTPAREN:
+ fmtprint(f, "(");
+ exprfmt(f, n->left, 0);
+ fmtprint(f, ")");
+ break;
case OTMAP:
fmtprint(f, "map[");
@@ -178,7 +209,7 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 0);
} else {
fmtprint(f, " ");
- if(n->left->op == OTCHAN && n->left->etype == Crecv) {
+ if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
fmtprint(f, "(");
exprfmt(f, n->left, 0);
fmtprint(f, ")");
@@ -248,6 +279,10 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 0);
break;
+ case OCLOSURE:
+ fmtprint(f, "func literal");
+ break;
+
case OCOMPLIT:
fmtprint(f, "composite literal");
break;
@@ -267,6 +302,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "struct literal");
break;
+ case OXDOT:
case ODOT:
case ODOTPTR:
case ODOTINTER:
@@ -274,8 +310,15 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 7);
if(n->right == N || n->right->sym == S)
fmtprint(f, ".<nil>");
- else
- fmtprint(f, ".%s", n->right->sym->name);
+ else {
+ // skip leading type· in method name
+ p = utfrrune(n->right->sym->name, 0xb7);
+ if(p)
+ p+=2;
+ else
+ p = n->right->sym->name;
+ fmtprint(f, ".%s", p);
+ }
break;
case ODOTTYPE:
@@ -291,7 +334,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OINDEX:
case OINDEXMAP:
- case OINDEXSTR:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
exprfmt(f, n->right, 0);
@@ -299,9 +341,12 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OSLICE:
+ case OSLICESTR:
+ case OSLICEARR:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
- exprfmt(f, n->right->left, 0);
+ if(n->right->left != N)
+ exprfmt(f, n->right->left, 0);
fmtprint(f, ":");
if(n->right->right != N)
exprfmt(f, n->right->right, 0);
@@ -315,6 +360,8 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 7);
fmtprint(f, "(");
exprlistfmt(f, n->list);
+ if(n->isddd)
+ fmtprint(f, "...");
fmtprint(f, ")");
break;
@@ -341,7 +388,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OCONV:
case OCONVIFACE:
case OCONVNOP:
- case OCONVSLICE:
case OARRAYBYTESTR:
case ORUNESTR:
if(n->type == T || n->type->sym == S)
@@ -355,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, ")");
break;
+ case OAPPEND:
case OCAP:
case OCLOSE:
case OCLOSED:
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index 09d54b3ee..dca3a5454 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -24,6 +24,8 @@ typecheckrange(Node *n)
typecheck(&n->right, Erv);
if((t = n->right->type) == T)
goto out;
+ if(isptr[t->etype] && isfixedarray(t->type))
+ t = t->type;
n->type = t;
switch(t->etype) {
@@ -104,9 +106,6 @@ walkrange(Node *n)
a = nod(OCONV, n->right, N);
a->type = types[TSTRING];
}
- ha = nod(OXXX, N, N);
- tempname(ha, a->type);
- init = list(init, nod(OAS, ha, a));
v1 = n->list->n;
hv1 = N;
@@ -116,6 +115,16 @@ walkrange(Node *n)
v2 = n->list->next->n;
hv2 = N;
+ if(v2 == N && t->etype == TARRAY) {
+ // will have just one reference to argument.
+ // no need to make a potentially expensive copy.
+ ha = a;
+ } else {
+ ha = nod(OXXX, N, N);
+ tempname(ha, a->type);
+ init = list(init, nod(OAS, ha, a));
+ }
+
switch(t->etype) {
default:
fatal("walkrange");
@@ -131,7 +140,7 @@ walkrange(Node *n)
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
if(v2) {
hp = nod(OXXX, N, N);
- tempname(hp, ptrto(a->type->type));
+ tempname(hp, ptrto(n->type->type));
tmp = nod(OINDEX, ha, nodintconst(0));
tmp->etype = 1; // no bounds check
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 467f3615b..b31eb5154 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -100,16 +100,16 @@ lsort(Sig *l, int(*f)(Sig*, Sig*))
* return function type, receiver as first argument (or not).
*/
Type*
-methodfunc(Type *f, int use_receiver)
+methodfunc(Type *f, Type *receiver)
{
NodeList *in, *out;
Node *d;
Type *t;
in = nil;
- if(use_receiver) {
+ if(receiver) {
d = nod(ODCLFIELD, N, N);
- d->type = getthisx(f)->type->type;
+ d->type = receiver;
in = list(in, d);
}
for(t=getinargx(f)->type; t; t=t->down) {
@@ -183,14 +183,14 @@ methods(Type *t)
a = b;
a->name = method->name;
- a->isym = methodsym(method, it);
- a->tsym = methodsym(method, t);
- a->type = methodfunc(f->type, 1);
- a->mtype = methodfunc(f->type, 0);
+ a->isym = methodsym(method, it, 1);
+ a->tsym = methodsym(method, t, 0);
+ a->type = methodfunc(f->type, t);
+ a->mtype = methodfunc(f->type, nil);
if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen;
- if(!eqtype(this, it)) {
+ if(!eqtype(this, it) || this->width < types[tptr]->width) {
if(oldlist == nil)
oldlist = pc;
// Is okay to call genwrapper here always,
@@ -199,9 +199,9 @@ methods(Type *t)
// is a pointer adjustment and a JMP.
if(isptr[it->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f->type))
- genembedtramp(it, f, a->isym);
+ genembedtramp(it, f, a->isym, 1);
else
- genwrapper(it, f, a->isym);
+ genwrapper(it, f, a->isym, 1);
}
}
@@ -212,9 +212,9 @@ methods(Type *t)
oldlist = pc;
if(isptr[t->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f->type))
- genembedtramp(t, f, a->tsym);
+ genembedtramp(t, f, a->tsym, 0);
else
- genwrapper(t, f, a->tsym);
+ genwrapper(t, f, a->tsym, 0);
}
}
}
@@ -241,22 +241,27 @@ imethods(Type *t)
Sig *a, *all, *last;
int o;
Type *f;
+ Sym *method, *isym;
+ Prog *oldlist;
all = nil;
last = nil;
o = 0;
+ oldlist = nil;
for(f=t->type; f; f=f->down) {
if(f->etype != TFIELD)
fatal("imethods: not field");
if(f->type->etype != TFUNC || f->sym == nil)
continue;
+ method = f->sym;
a = mal(sizeof(*a));
- a->name = f->sym->name;
- if(!exportname(f->sym->name))
- a->pkg = f->sym->pkg;
+ a->name = method->name;
+ if(!exportname(method->name))
+ a->pkg = method->pkg;
a->mtype = f->type;
a->offset = 0;
- a->type = methodfunc(f->type, 0);
+ a->type = methodfunc(f->type, nil);
+
if(last && sigcmp(last, a) >= 0)
fatal("sigcmp vs sortinter %s %s", last->name, a->name);
if(last == nil)
@@ -264,7 +269,34 @@ imethods(Type *t)
else
last->link = a;
last = a;
+
+ // Compiler can only refer to wrappers for
+ // named interface types.
+ if(t->sym == S)
+ continue;
+
+ // NOTE(rsc): Perhaps an oversight that
+ // IfaceType.Method is not in the reflect data.
+ // Generate the method body, so that compiled
+ // code can refer to it.
+ isym = methodsym(method, t, 0);
+ if(!(isym->flags & SymSiggen)) {
+ isym->flags |= SymSiggen;
+ if(oldlist == nil)
+ oldlist = pc;
+ genwrapper(t, f, isym, 0);
+ }
}
+
+ if(oldlist) {
+ // old list ended with AEND; change to ANOP
+ // so that the trampolines that follow can be found.
+ nopout(oldlist);
+
+ // start new data list
+ newplist();
+ }
+
return all;
}
@@ -545,7 +577,6 @@ dcommontype(Sym *s, int ot, Type *t)
{
int i;
Sym *s1;
- Type *elem;
char *p;
dowidth(t);
@@ -566,26 +597,23 @@ dcommontype(Sym *s, int ot, Type *t)
// alg uint8;
// align uint8;
// fieldAlign uint8;
+ // kind uint8;
// string *string;
// *nameInfo;
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
ot = duint8(s, ot, algtype(t));
- elem = t;
- while(elem->etype == TARRAY && elem->bound >= 0)
- elem = elem->type;
- i = elem->width;
- if(i > maxround)
- i = maxround;
- ot = duint8(s, ot, i); // align
- ot = duint8(s, ot, i); // fieldAlign
+ ot = duint8(s, ot, t->align); // align
+ ot = duint8(s, ot, t->align); // fieldAlign
i = kinds[t->etype];
if(t->etype == TARRAY && t->bound < 0)
i = KindSlice;
+ if(isptr[t->etype] && t->type->etype == TANY)
+ i = KindUnsafePointer;
if(!haspointers(t))
i |= KindNoPointers;
- ot = duint8(s, ot, i);
+ ot = duint8(s, ot, i); // kind
longsymnames = 1;
p = smprint("%-T", t);
longsymnames = 0;
@@ -643,11 +671,10 @@ typename(Type *t)
static Sym*
dtypesym(Type *t)
{
- int ot, n, isddd;
+ int ot, n, isddd, dupok;
Sym *s, *s1, *s2;
Sig *a, *m;
- Type *t1;
- Sym *tsym;
+ Type *t1, *tbase;
if(isideal(t))
fatal("dtypesym %T", t);
@@ -660,30 +687,22 @@ dtypesym(Type *t)
// special case (look for runtime below):
// when compiling package runtime,
// emit the type structures for int, float, etc.
- t1 = T;
- if(isptr[t->etype])
- t1 = t->type;
- tsym = S;
- if(t1)
- tsym = t1->sym;
- else
- tsym = t->sym;
+ tbase = t;
+ if(isptr[t->etype] && t->sym == S && t->type->sym != S)
+ tbase = t->type;
+ dupok = tbase->sym == S;
if(compiling_runtime) {
- if(t == types[t->etype])
+ if(tbase == types[tbase->etype]) // int, float, etc
goto ok;
- if(t1 && t1 == types[t1->etype])
- goto ok;
- if(t1 && t1->etype == tptr && t1->type->etype == TANY)
+ if(tbase->etype == tptr && tbase->type->etype == TANY) // unsafe.Pointer
goto ok;
}
- // named types from other files are defined in those files
- if(t->sym && !t->local)
- return s;
- if(!t->sym && t1 && t1->sym && !t1->local)
+ // named types from other files are defined only by those files
+ if(tbase->sym && !tbase->local)
return s;
- if(isforw[t->etype] || (t1 && isforw[t1->etype]))
+ if(isforw[tbase->etype])
return s;
ok:
@@ -778,6 +797,7 @@ ok:
case TPTR32:
case TPTR64:
if(t->type->etype == TANY) {
+ // ../../pkg/runtime/type.go:/UnsafePointerType
ot = dcommontype(s, ot, t);
break;
}
@@ -818,7 +838,7 @@ ok:
break;
}
- ggloblsym(s, ot, tsym == nil);
+ ggloblsym(s, ot, dupok);
return s;
}
@@ -846,7 +866,7 @@ dumptypestructs(void)
continue;
t = n->type;
dtypesym(t);
- if(t->sym && !isptr[t->etype])
+ if(t->sym)
dtypesym(ptrto(t));
}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 5783faafd..174bc050e 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -10,7 +10,7 @@ package PACKAGE
// emitted by compiler, not referred to by go programs
-func mal(int32) *any
+func new(int32) *any
func panicindex()
func panicslice()
func throwreturn()
@@ -31,13 +31,18 @@ func printeface(any)
func printslice(any)
func printnl()
func printsp()
-func printf()
+func goprintf()
+
+// filled in by compiler: int n, string, string, ...
+func concatstring()
+
+// filled in by compiler: Type*, int n, Slice, ...
+func append()
+func appendslice(typ *byte, x any, y []any) any
-func catstring(string, string) string
func cmpstring(string, string) int
func slicestring(string, int, int) string
func slicestring1(string, int) string
-func indexstring(string, int) byte
func intstring(int64) string
func slicebytetostring([]byte) string
func sliceinttostring([]int) string
@@ -46,6 +51,7 @@ func stringtosliceint(string) []int
func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int)
func slicecopy(to any, fr any, wid uint32) int
+func slicestringcopy(to any, fr any) int
// interface conversions
func convI2E(elem any) (ret any)
@@ -99,9 +105,9 @@ func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func sliceslice1(old []any, lb int, width int) (ary []any)
-func sliceslice(old []any, lb int, hb int, width int) (ary []any)
-func slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
+func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
+func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
+func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
func closure() // has args, but compiler fills in
@@ -111,6 +117,8 @@ func uint64div(uint64, uint64) uint64
func int64mod(int64, int64) int64
func uint64mod(uint64, uint64) uint64
func float64toint64(float64) int64
+func float64touint64(float64) uint64
func int64tofloat64(int64) float64
+func uint64tofloat64(uint64) float64
func complex128div(num complex128, den complex128) (quo complex128)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 9cba01fa5..1a3771311 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -41,11 +41,18 @@ typecheckselect(Node *sel)
setlineno(n);
switch(n->op) {
default:
- yyerror("select case must be receive, send or assign recv");;
+ yyerror("select case must be receive, send or assign recv");
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.
+ 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;
@@ -68,8 +75,6 @@ typecheckselect(Node *sel)
typechecklist(ncase->nbody, Etop);
}
sel->xoffset = count;
- if(count == 0)
- yyerror("empty select");
lineno = lno;
}
@@ -91,7 +96,7 @@ walkselect(Node *sel)
typecheck(&r, Etop);
init = list(init, r);
- if(sel->list == nil)
+ if(sel->list == nil && sel->xoffset != 0)
fatal("double walkselect"); // already rewrote
// register cases
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 5ac14a537..19ee3327b 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -92,15 +92,9 @@ init1(Node *n, NodeList **out)
break;
case OAS2FUNC:
- if(n->defn->initorder)
- break;
- n->defn->initorder = 1;
- for(l=n->defn->rlist; l; l=l->next)
- init1(l->n, out);
- *out = list(*out, n->defn);
- break;
-
case OAS2MAPR:
+ case OAS2DOTTYPE:
+ case OAS2RECV:
if(n->defn->initorder)
break;
n->defn->initorder = 1;
@@ -190,6 +184,20 @@ static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
+static Node*
+staticname(Type *t, int ctxt)
+{
+ Node *n;
+
+ snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
+ statuniqgen++;
+ n = newname(lookup(namebuf));
+ if(!ctxt)
+ n->readonly = 1;
+ addvar(n, t, PEXTERN);
+ return n;
+}
+
static int
isliteral(Node *n)
{
@@ -402,12 +410,12 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt != 0) {
// put everything into static array
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(ctxt, 1, n, vstat, init);
arraylit(ctxt, 2, n, vstat, init);
// copy static to slice
- a = nod(OADDR, vstat, N);
+ a = nod(OSLICE, vstat, nod(OKEY, N, N));
a = nod(OAS, var, a);
typecheck(&a, Etop);
a->dodata = 2;
@@ -439,7 +447,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
vstat = N;
mode = getdyn(n, 1);
if(mode & MODECONST) {
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(ctxt, 1, n, vstat, init);
}
@@ -465,7 +473,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
}
// make slice out of heap (5)
- a = nod(OAS, var, vauto);
+ a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
@@ -514,6 +522,8 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
Node *vstat, *index, *value;
Sym *syma, *symb;
+ctxt = 0;
+
// make the map var
nerr = nerrors;
@@ -566,7 +576,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
dowidth(t);
// make and initialize static array
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
b = 0;
for(l=n->list; l; l=l->next) {
r = l->n;
@@ -675,7 +685,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt == 0) {
// lay out static data
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
structlit(1, 1, n, vstat, init);
// copy static to var
@@ -715,7 +725,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt == 0) {
// lay out static data
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(1, 1, n, vstat, init);
// copy static to automatic
@@ -769,8 +779,8 @@ oaslit(Node *n, NodeList **init)
// implies generated data executed
// exactly once and not subject to races.
ctxt = 0;
- if(n->dodata == 1)
- ctxt = 1;
+// if(n->dodata == 1)
+// ctxt = 1;
switch(n->right->op) {
default:
@@ -870,8 +880,18 @@ gen_as_init(Node *n)
default:
goto no;
- case OCONVSLICE:
- goto slice;
+ case OCONVNOP:
+ nr = nr->left;
+ if(nr == N || nr->op != OSLICEARR)
+ goto no;
+ // fall through
+
+ case OSLICEARR:
+ if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
+ nr = nr->left;
+ goto slice;
+ }
+ goto no;
case OLITERAL:
break;
@@ -920,7 +940,7 @@ yes:
slice:
gused(N); // in case the data is the dest of a goto
- nr = n->right->left;
+ nl = nr;
if(nr == N || nr->op != OADDR)
goto no;
nr = nr->left;
@@ -932,7 +952,7 @@ slice:
goto no;
nam.xoffset += Array_array;
- gdata(&nam, n->right->left, types[tptr]->width);
+ gdata(&nam, nl, types[tptr]->width);
nam.xoffset += Array_nel-Array_array;
nodconst(&nod1, types[TINT32], nr->type->bound);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 65b56dee6..3c4501096 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -228,11 +228,15 @@ linehist(char *file, int32 off, int relative)
if(debug['i']) {
if(file != nil) {
if(off < 0)
- print("pragma %s at line %L\n", file, lineno);
+ print("pragma %s", file);
else
- print("import %s at line %L\n", file, lineno);
+ if(off > 0)
+ print("line %s", file);
+ else
+ print("import %s", file);
} else
- print("end of import at line %L\n", lineno);
+ print("end of import");
+ print(" at line %L\n", lexlineno);
}
if(off < 0 && file[0] != '/' && !relative) {
@@ -267,7 +271,6 @@ setlineno(Node *n)
case OTYPE:
case OPACK:
case OLITERAL:
- case ONONAME:
break;
default:
lineno = n->lineno;
@@ -360,6 +363,8 @@ importdot(Pkg *opkg, Node *pack)
for(s = hash[h]; s != S; s = s->link) {
if(s->pkg != opkg)
continue;
+ if(s->def == N)
+ continue;
if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot
continue;
s1 = lookup(s->name);
@@ -473,9 +478,12 @@ algtype(Type *t)
int a;
if(issimple[t->etype] || isptr[t->etype] || iscomplex[t->etype] ||
- t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP)
- a = AMEM; // just bytes (int, ptr, etc)
- else if(t->etype == TSTRING)
+ t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
+ if(t->width == widthptr)
+ a = AMEMWORD;
+ else
+ a = AMEM; // just bytes (int, ptr, etc)
+ } else if(t->etype == TSTRING)
a = ASTRING; // string
else if(isnilinter(t))
a = ANILINTER; // nil interface
@@ -584,6 +592,21 @@ nodintconst(int64 v)
return c;
}
+Node*
+nodfltconst(Mpflt* v)
+{
+ Node *c;
+
+ c = nod(OLITERAL, N, N);
+ c->addable = 1;
+ c->val.u.fval = mal(sizeof(*c->val.u.fval));
+ mpmovefltflt(c->val.u.fval, v);
+ c->val.ctype = CTFLT;
+ c->type = types[TIDEAL];
+ ullmancalc(c);
+ return c;
+}
+
void
nodconst(Node *n, Type *t, int64 v)
{
@@ -804,6 +827,7 @@ goopnames[] =
[OANDAND] = "&&",
[OANDNOT] = "&^",
[OAND] = "&",
+ [OAPPEND] = "append",
[OAS] = "=",
[OAS2] = "=",
[OBREAK] = "break",
@@ -894,12 +918,21 @@ Lconv(Fmt *fp)
if(lno < h->line)
break;
if(h->name) {
- if(n < HISTSZ) { /* beginning of file */
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
+ if(h->offset > 0) {
+ // #line directive
+ if(n > 0 && n < HISTSZ) {
+ a[n-1].line = h;
+ a[n-1].ldel = h->line - h->offset + 1;
+ }
+ } else {
+ // beginning of file
+ if(n < HISTSZ) {
+ a[n].incl = h;
+ a[n].idel = h->line;
+ a[n].line = 0;
+ }
+ n++;
}
- n++;
continue;
}
n--;
@@ -919,14 +952,16 @@ Lconv(Fmt *fp)
break;
fmtprint(fp, " ");
}
+ if(debug['L'])
+ fmtprint(fp, "%s/", pathname);
if(a[i].line)
- fmtprint(fp, "%s:%ld[%s:%ld]",
+ fmtprint(fp, "%s:%d[%s:%d]",
a[i].line->name, lno-a[i].ldel+1,
a[i].incl->name, lno-a[i].idel+1);
else
- fmtprint(fp, "%s:%ld",
+ fmtprint(fp, "%s:%d",
a[i].incl->name, lno-a[i].idel+1);
- lno = a[i].incl->line - 1; /* now print out start of this file */
+ lno = a[i].incl->line - 1; // now print out start of this file
}
if(n == 0)
fmtprint(fp, "<epoch>");
@@ -1003,10 +1038,10 @@ Jconv(Fmt *fp)
fmtprint(fp, " a(%d)", n->addable);
if(n->vargen != 0)
- fmtprint(fp, " g(%ld)", n->vargen);
+ fmtprint(fp, " g(%d)", n->vargen);
if(n->lineno != 0)
- fmtprint(fp, " l(%ld)", n->lineno);
+ fmtprint(fp, " l(%d)", n->lineno);
if(n->xoffset != 0)
fmtprint(fp, " x(%lld)", n->xoffset);
@@ -1029,6 +1064,9 @@ Jconv(Fmt *fp)
if(n->isddd != 0)
fmtprint(fp, " isddd(%d)", n->isddd);
+ if(n->implicit != 0)
+ fmtprint(fp, " implicit(%d)", n->implicit);
+
return 0;
}
@@ -1146,7 +1184,7 @@ Tpretty(Fmt *fp, Type *t)
case Csend:
return fmtprint(fp, "chan<- %T", t->type);
}
- if(t->type != T && t->type->etype == TCHAN && t->type->chan == Crecv)
+ if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
return fmtprint(fp, "chan (%T)", t->type);
return fmtprint(fp, "chan %T", t->type);
@@ -1256,7 +1294,7 @@ Tpretty(Fmt *fp, Type *t)
fmtprint(fp, "...%T", t->type->type);
else
fmtprint(fp, "%T", t->type);
- if(t->note) {
+ if(t->note) {
fmtprint(fp, " ");
if(exporting)
fmtprint(fp, ":");
@@ -1360,7 +1398,7 @@ Tconv(Fmt *fp)
case TARRAY:
if(t->bound >= 0)
- fmtprint(fp, "[%ld]%T", t->bound, t->type);
+ fmtprint(fp, "[%d]%T", t->bound, t->type);
else
fmtprint(fp, "[]%T", t->type);
break;
@@ -1414,7 +1452,7 @@ Nconv(Fmt *fp)
fmtprint(fp, "%O%J", n->op, n);
break;
}
- fmtprint(fp, "%O-%S G%ld%J", n->op,
+ fmtprint(fp, "%O-%S G%d%J", n->op,
n->sym, n->vargen, n);
goto ptyp;
@@ -1460,7 +1498,7 @@ Nconv(Fmt *fp)
break;
}
if(n->sym != S)
- fmtprint(fp, " %S G%ld", n->sym, n->vargen);
+ fmtprint(fp, " %S G%d", n->sym, n->vargen);
ptyp:
if(n->type != T)
@@ -1909,13 +1947,6 @@ assignop(Type *src, Type *dst, char **why)
// 7. Any typed value can be assigned to the blank identifier.
if(dst->etype == TBLANK)
return OCONVNOP;
-
- // 8. Array to slice.
- // TODO(rsc): Not for long.
- if(!src->sym || !dst->sym)
- if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst))
- if(eqtype(src->type->type, dst->type))
- return OCONVSLICE;
return 0;
}
@@ -2037,6 +2068,7 @@ assignconv(Node *n, Type *t, char *context)
r = nod(op, n, N);
r->type = t;
r->typecheck = 1;
+ r->implicit = 1;
return r;
}
@@ -2292,7 +2324,8 @@ ptrto(Type *t)
fatal("ptrto: nil");
t1 = typ(tptr);
t1->type = t;
- t1->width = types[tptr]->width;
+ t1->width = widthptr;
+ t1->align = widthptr;
return t1;
}
@@ -2320,7 +2353,7 @@ frame(int context)
case ONAME:
if(flag)
print("--- %s frame ---\n", p);
- print("%O %S G%ld %T\n", n->op, n->sym, n->vargen, n->type);
+ print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
flag = 0;
break;
@@ -2584,20 +2617,8 @@ brrev(int a)
return a;
}
-Node*
-staticname(Type *t)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
- statuniqgen++;
- n = newname(lookup(namebuf));
- addvar(n, t, PEXTERN);
- return n;
-}
-
/*
- * return side effect-free appending side effects to init.
+ * return side effect-free n, appending side effects to init.
* result is assignable if n is.
*/
Node*
@@ -2654,6 +2675,24 @@ safeexpr(Node *n, NodeList **init)
// make a copy; must not be used as an lvalue
if(islvalue(n))
fatal("missing lvalue case in safeexpr: %N", n);
+ return cheapexpr(n, init);
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+Node*
+cheapexpr(Node *n, NodeList **init)
+{
+ Node *a, *l;
+
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+
l = nod(OXXX, N, N);
tempname(l, n->type);
a = nod(OAS, l, n);
@@ -2939,6 +2978,11 @@ expandmeth(Sym *s, Type *t)
if(t == T || t->xmethod != nil)
return;
+ // mark top-level method symbols
+ // so that expand1 doesn't consider them.
+ for(f=t->method; f != nil; f=f->down)
+ f->sym->flags |= SymUniq;
+
// generate all reachable methods
slist = nil;
expand1(t, nelem(dotlist)-1, 0);
@@ -2958,6 +3002,9 @@ expandmeth(Sym *s, Type *t)
}
}
+ for(f=t->method; f != nil; f=f->down)
+ f->sym->flags &= ~SymUniq;
+
t->xmethod = t->method;
for(sl=slist; sl!=nil; sl=sl->link) {
if(sl->good) {
@@ -2969,7 +3016,6 @@ expandmeth(Sym *s, Type *t)
f->embedded = 2;
f->down = t->xmethod;
t->xmethod = f;
-
}
}
}
@@ -3031,15 +3077,19 @@ structargs(Type **tl, int mustname)
* newnam - the eventual mangled name of this function
*/
void
-genwrapper(Type *rcvr, Type *method, Sym *newnam)
+genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
{
- Node *this, *fn, *call, *n, *t;
+ Node *this, *fn, *call, *n, *t, *pad;
NodeList *l, *args, *in, *out;
+ Type *tpad;
+ int isddd;
if(debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
+ lineno = 1; // less confusing than end of input
+
dclcontext = PEXTERN;
markdcl();
@@ -3050,20 +3100,37 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(newnam);
- t = nod(OTFUNC, this, N);
- t->list = in;
+ t = nod(OTFUNC, N, N);
+ l = list1(this);
+ if(iface && rcvr->width < types[tptr]->width) {
+ // Building method for interface table and receiver
+ // is smaller than the single pointer-sized word
+ // that the interface call will pass in.
+ // Add a dummy padding argument after the
+ // receiver to make up the difference.
+ tpad = typ(TARRAY);
+ tpad->type = types[TUINT8];
+ tpad->bound = types[tptr]->width - rcvr->width;
+ pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
+ l = list(l, pad);
+ }
+ t->list = concat(l, in);
t->rlist = out;
fn->nname->ntype = t;
funchdr(fn);
// arg list
args = nil;
- for(l=in; l; l=l->next)
+ isddd = 0;
+ for(l=in; l; l=l->next) {
args = list(args, l->n->left);
+ isddd = l->n->left->isddd;
+ }
// generate call
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
call->list = args;
+ call->isddd = isddd;
fn->nbody = list1(call);
if(method->type->outtuple > 0) {
n = nod(ORETURN, N, N);
@@ -3563,10 +3630,11 @@ umagic(Magic *m)
Sym*
ngotype(Node *n)
{
- if(n->sym != S && strncmp(n->sym->name, "autotmp_", 8) != 0)
- if(n->type->etype != TFUNC || n->type->thistuple == 0)
- if(n->type->etype != TSTRUCT || n->type->funarg == 0)
- return typename(n->type)->left->sym;
+ if(n->sym != S && n->realtype != T)
+ if(strncmp(n->sym->name, "autotmp_", 8) != 0)
+ if(strncmp(n->sym->name, "statictmp_", 8) != 0)
+ return typename(n->realtype)->left->sym;
+
return S;
}
@@ -3640,4 +3708,3 @@ strlit(char *s)
t->len = strlen(s);
return t;
}
-
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 457b82b4c..ca114d47c 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -17,7 +17,8 @@ static void implicitstar(Node**);
static int onearg(Node*, char*, ...);
static int twoarg(Node*);
static int lookdot(Node*, Type*, int);
-static void typecheckaste(int, Type*, NodeList*, char*);
+static int looktypedot(Node*, Type*, int);
+static void typecheckaste(int, int, Type*, NodeList*, char*);
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
@@ -63,7 +64,7 @@ typechecklist(NodeList *l, int top)
Node*
typecheck(Node **np, int top)
{
- int et, op, ptr;
+ int et, aop, op, ptr;
Node *n, *l, *r;
NodeList *args;
int lno, ok, ntop;
@@ -79,7 +80,7 @@ typecheck(Node **np, int top)
n = *np;
if(n == N)
return N;
-
+
// Resolve definition of name and value of iota lazily.
n = resolve(n);
*np = n;
@@ -111,6 +112,7 @@ typecheck(Node **np, int top)
goto error;
}
walkdef(n);
+ n->realtype = n->type;
if(n->op == ONONAME)
goto error;
}
@@ -169,6 +171,16 @@ reswitch:
goto error;
break;
+ case OTPAREN:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ if(l->type == T)
+ goto error;
+ n->op = OTYPE;
+ n->type = l->type;
+ n->left = N;
+ break;
+
case OTARRAY:
ok |= Etype;
t = typ(TARRAY);
@@ -251,7 +263,6 @@ reswitch:
n->type = dostruct(n->list, TINTER);
if(n->type == T)
goto error;
- n->type = sortinter(n->type);
break;
case OTFUNC:
@@ -340,6 +351,26 @@ reswitch:
et = t->etype;
if(et == TIDEAL)
et = TINT;
+ if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+ // comparison is okay as long as one side is
+ // assignable to the other. convert so they have
+ // the same type. (the only conversion that isn't
+ // a no-op is concrete == interface.)
+ if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
+ l = nod(aop, l, N);
+ l->type = r->type;
+ l->typecheck = 1;
+ n->left = l;
+ t = l->type;
+ } else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
+ r = nod(aop, r, N);
+ r->type = l->type;
+ r->typecheck = 1;
+ n->right = r;
+ t = r->type;
+ }
+ et = t->etype;
+ }
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
badbinary:
defaultlit2(&l, &r, 1);
@@ -393,7 +424,7 @@ reswitch:
n->right = r;
t = r->type;
if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %#N (shift count type %T)", n, r->type);
+ yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
goto error;
}
t = l->type;
@@ -467,41 +498,42 @@ reswitch:
yyerror("rhs of . must be a name"); // impossible
goto error;
}
- if(isptr[t->etype]) {
- t = t->type;
- if(t == T)
- goto error;
- n->op = ODOTPTR;
- checkwidth(t);
- }
sym = n->right->sym;
- if(!lookdot(n, t, 0)) {
- if(lookdot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
- goto error;
- }
if(l->op == OTYPE) {
- if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, sym);
- n->type = T;
+ if(!looktypedot(n, t, 0)) {
+ if(looktypedot(n, t, 1))
+ yyerror("%#N undefined (cannot refer to unexported method %S)", n, n->right->sym);
+ else
+ yyerror("%#N undefined (type %T has no method %S)", n, t, n->right->sym);
goto error;
}
- if(t->etype == TINTER) {
- yyerror("method expression on interface not implemented");
+ if(n->type->etype != TFUNC || n->type->thistuple != 1) {
+ yyerror("type %T has no method %hS", n->left->type, sym);
n->type = T;
goto error;
}
n->op = ONAME;
- n->sym = methodsym(sym, l->type);
- n->type = methodfunc(n->type, 1);
+ n->sym = methodsym(sym, l->type, 0);
+ n->type = methodfunc(n->type, l->type);
n->xoffset = 0;
- getinargx(n->type)->type->type = l->type; // fix up receiver
n->class = PFUNC;
ok = Erv;
goto ret;
}
+ if(isptr[t->etype] && t->type->etype != TINTER) {
+ t = t->type;
+ if(t == T)
+ goto error;
+ n->op = ODOTPTR;
+ checkwidth(t);
+ }
+ if(!lookdot(n, t, 0)) {
+ if(lookdot(n, t, 1))
+ yyerror("%#N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
+ else
+ yyerror("%#N undefined (type %T has no field or method %S)", n, t, n->right->sym);
+ goto error;
+ }
switch(n->op) {
case ODOTINTER:
case ODOTMETH:
@@ -561,7 +593,7 @@ reswitch:
goto error;
case TARRAY:
- defaultlit(&n->right, types[TUINT]);
+ defaultlit(&n->right, T);
if(n->right->type != T && !isint[n->right->type->etype])
yyerror("non-integer array index %#N", n->right);
n->type = t->type;
@@ -581,7 +613,6 @@ reswitch:
if(n->right->type != T && !isint[n->right->type->etype])
yyerror("non-integer string index %#N", n->right);
n->type = types[TUINT8];
- n->op = OINDEXSTR;
break;
}
goto ret;
@@ -612,6 +643,10 @@ reswitch:
l = n->left;
if((t = l->type) == T)
goto error;
+ if(t->etype != TCHAN) {
+ yyerror("invalid operation: %#N (send to non-chan type %T)", n, t);
+ goto error;
+ }
if(!(t->chan & Csend)) {
yyerror("invalid operation: %#N (send to receive-only type %T)", n, t);
goto error;
@@ -620,6 +655,7 @@ reswitch:
r = n->right;
if((t = r->type) == T)
goto error;
+ r = assignconv(r, l->type->type, "send");
// TODO: more aggressive
n->etype = 0;
n->type = T;
@@ -635,24 +671,19 @@ reswitch:
typecheck(&n->right->left, Erv);
typecheck(&n->right->right, Erv);
defaultlit(&n->left, T);
- defaultlit(&n->right->left, types[TUINT]);
- defaultlit(&n->right->right, types[TUINT]);
+ defaultlit(&n->right->left, T);
+ defaultlit(&n->right->right, T);
if(isfixedarray(n->left->type)) {
- // Insert explicit & before fixed array
- // so that back end knows to move to heap.
n->left = nod(OADDR, n->left, N);
typecheck(&n->left, top);
}
- implicitstar(&n->left);
- if(n->right->left == N) {
- yyerror("missing slice bounds?");
- goto error;
- }
- if((t = n->right->left->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->left, t);
- goto error;
+ if(n->right->left != N) {
+ if((t = n->right->left->type) == T)
+ goto error;
+ if(!isint[t->etype]) {
+ yyerror("invalid slice index %#N (type %T)", n->right->left, t);
+ goto error;
+ }
}
if(n->right->right != N) {
if((t = n->right->right->type) == T)
@@ -670,9 +701,9 @@ reswitch:
n->op = OSLICESTR;
goto ret;
}
- if(isfixedarray(t)) {
+ if(isptr[t->etype] && isfixedarray(t->type)) {
n->type = typ(TARRAY);
- n->type->type = t->type;
+ n->type->type = t->type->type;
n->type->bound = -1;
dowidth(n->type);
n->op = OSLICEARR;
@@ -690,13 +721,17 @@ reswitch:
*/
case OCALL:
l = n->left;
- if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) {
+ if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
+ if(n->isddd)
+ yyerror("invalid use of ... with builtin %#N", l);
n = r;
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall);
l = n->left;
if(l->op == ONAME && l->etype != 0) {
+ if(n->isddd && l->etype != OAPPEND)
+ yyerror("invalid use of ... with builtin %#N", l);
// builtin: OLEN, OCAP, etc.
n->op = l->etype;
n->left = n->right;
@@ -706,6 +741,8 @@ reswitch:
defaultlit(&n->left, T);
l = n->left;
if(l->op == OTYPE) {
+ if(n->isddd)
+ yyerror("invalid use of ... in type conversion", l);
// pick off before type-checking arguments
ok |= Erv;
// turn CALL(type, arg) into CONV(arg) w/ type
@@ -732,7 +769,7 @@ reswitch:
case ODOTMETH:
n->op = OCALLMETH;
- typecheckaste(OCALL, getthisx(t), list1(l->left), "method receiver");
+ typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver");
break;
default:
@@ -743,7 +780,7 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, getinargx(t), n->list, "function argument");
+ typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument");
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -792,6 +829,12 @@ reswitch:
case OIMAG:
if(!iscomplex[t->etype])
goto badcall1;
+ if(isconst(l, CTCPLX)){
+ if(n->op == OREAL)
+ n = nodfltconst(&l->val.u.cval->real);
+ else
+ n = nodfltconst(&l->val.u.cval->imag);
+ }
n->type = types[cplxsubtype(t->etype)];
goto ret;
}
@@ -802,7 +845,7 @@ reswitch:
nodconst(n, types[TINT], l->val.u.sval->len);
break;
case TARRAY:
- if(t->bound >= 0)
+ if(t->bound >= 0 && l->op == ONAME)
nodconst(n, types[TINT], t->bound);
break;
}
@@ -868,6 +911,40 @@ reswitch:
ok |= Etop;
goto ret;
+ case OAPPEND:
+ ok |= Erv;
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing arguments to append");
+ goto error;
+ }
+ typechecklist(args, Erv);
+ if((t = args->n->type) == T)
+ goto error;
+ n->type = t;
+ if(!isslice(t)) {
+ yyerror("first argument to append must be slice; have %lT", t);
+ goto error;
+ }
+ if(n->isddd) {
+ if(args->next == nil) {
+ yyerror("cannot use ... on first argument to append");
+ goto error;
+ }
+ if(args->next->next != nil) {
+ yyerror("too many arguments to append");
+ goto error;
+ }
+ args->next->n = assignconv(args->next->n, t->orig, "append");
+ goto ret;
+ }
+ for(args=args->next; args != nil; args=args->next) {
+ if(args->n->type == T)
+ continue;
+ args->n = assignconv(args->n, t->type, "append");
+ }
+ goto ret;
+
case OCOPY:
ok |= Etop|Erv;
args = n->list;
@@ -888,13 +965,18 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
+
+ // copy([]byte, string)
+ if(isslice(n->left->type) && n->left->type->type == types[TUINT8] && n->right->type->etype == TSTRING)
+ goto ret;
+
if(!isslice(n->left->type) || !isslice(n->right->type)) {
if(!isslice(n->left->type) && !isslice(n->right->type))
yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
else if(!isslice(n->left->type))
yyerror("first argument to copy should be slice; have %lT", n->left->type);
else
- yyerror("second argument to copy should be slice; have %lT", n->right->type);
+ yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
goto error;
}
if(!eqtype(n->left->type->type, n->right->type->type)) {
@@ -1048,7 +1130,7 @@ reswitch:
case OPRINT:
case OPRINTN:
ok |= Etop;
- typechecklist(n->list, Erv);
+ typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
goto ret;
case OPANIC:
@@ -1056,7 +1138,7 @@ reswitch:
if(onearg(n, "panic") < 0)
goto error;
typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
+ defaultlit(&n->left, types[TINTER]);
if(n->left->type == T)
goto error;
goto ret;
@@ -1129,9 +1211,13 @@ reswitch:
case ORETURN:
ok |= Etop;
typechecklist(n->list, Erv | Efnstruct);
+ if(curfn == N) {
+ yyerror("return outside function");
+ goto error;
+ }
if(curfn->type->outnamed && n->list == nil)
goto ret;
- typecheckaste(ORETURN, getoutargx(curfn->type), n->list, "return argument");
+ typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument");
goto ret;
case OSELECT:
@@ -1149,11 +1235,6 @@ reswitch:
typecheckrange(n);
goto ret;
- case OTYPECASE:
- ok |= Etop | Erv;
- typecheck(&n->left, Erv);
- goto ret;
-
case OTYPESW:
yyerror("use of .(type) outside type switch");
goto error;
@@ -1218,7 +1299,7 @@ ret:
goto error;
}
if((ok & Ecall) && !(top & Ecall)) {
- yyerror("must call %#N", n);
+ yyerror("method %#N is not an expression, must be called", n);
goto error;
}
// TODO(rsc): simplify
@@ -1257,7 +1338,7 @@ implicitstar(Node **nn)
Type *t;
Node *n;
- // insert implicit * if needed
+ // insert implicit * if needed for fixed array
n = *nn;
t = n->type;
if(t == T || !isptr[t->etype])
@@ -1347,6 +1428,57 @@ lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
}
static int
+looktypedot(Node *n, Type *t, int dostrcmp)
+{
+ Type *f1, *f2, *tt;
+ Sym *s;
+
+ s = n->right->sym;
+
+ if(t->etype == TINTER) {
+ f1 = lookdot1(s, t, t->type, dostrcmp);
+ if(f1 == T)
+ return 0;
+
+ if(f1->width == BADWIDTH)
+ fatal("lookdot badwidth %T %p", f1, f1);
+ n->right = methodname(n->right, t);
+ n->xoffset = f1->width;
+ n->type = f1->type;
+ n->op = ODOTINTER;
+ return 1;
+ }
+
+ tt = t;
+ if(t->sym == S && isptr[t->etype])
+ tt = t->type;
+
+ f2 = methtype(tt);
+ if(f2 == T)
+ return 0;
+
+ expandmeth(f2->sym, f2);
+ f2 = lookdot1(s, f2, f2->xmethod, dostrcmp);
+ if(f2 == T)
+ return 0;
+
+ // disallow T.m if m requires *T receiver
+ if(isptr[getthisx(f2->type)->type->type->etype]
+ && !isptr[t->etype]
+ && f2->embedded != 2
+ && !isifacemethod(f2->type)) {
+ yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name);
+ return 0;
+ }
+
+ n->right = methodname(n->right, t);
+ n->xoffset = f2->width;
+ n->type = f2->type;
+ n->op = ODOTMETH;
+ return 1;
+}
+
+static int
lookdot(Node *n, Type *t, int dostrcmp)
{
Type *f1, *f2, *tt, *rcvr;
@@ -1359,9 +1491,15 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(t->etype == TSTRUCT || t->etype == TINTER)
f1 = lookdot1(s, t, t->type, dostrcmp);
- f2 = methtype(n->left->type);
- if(f2 != T)
- f2 = lookdot1(s, f2, f2->method, dostrcmp);
+ f2 = T;
+ if(n->left->type == t || n->left->type->sym == S) {
+ f2 = methtype(t);
+ if(f2 != T) {
+ // Use f2->method, not f2->xmethod: adddot has
+ // already inserted all the necessary embedded dots.
+ f2 = lookdot1(s, f2, f2->method, dostrcmp);
+ }
+ }
if(f1 != T) {
if(f2 != T)
@@ -1385,14 +1523,16 @@ lookdot(Node *n, Type *t, int dostrcmp)
tt = n->left->type;
dowidth(tt);
rcvr = getthisx(f2->type)->type->type;
- if(n->left->op != OTYPE && !eqtype(rcvr, tt)) {
+ if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on");
addrescapes(n->left);
n->left = nod(OADDR, n->left, N);
+ n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
} else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
n->left = nod(OIND, n->left, N);
+ n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
} else {
// method is attached to wrong type?
@@ -1422,7 +1562,7 @@ nokeys(NodeList *l)
* typecheck assignment: type list = expression list
*/
static void
-typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
+typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
{
Type *t, *tl, *tn;
Node *n;
@@ -1436,63 +1576,79 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
if(n->type->etype == TSTRUCT && n->type->funarg) {
- setlineno(n);
tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
- for(; tn; tn=tn->down)
+ 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);
+ }
goto out;
}
- if(tn == T) {
- yyerror("not enough arguments to %#O", op);
- 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);
tn = tn->down;
}
if(tn != T)
- yyerror("too many arguments to %#O", op);
+ goto toomany;
goto out;
}
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(tl->isddd) {
- if(nl != nil && nl->n->isddd && !eqtype(nl->n->type, t)) {
- // TODO(rsc): This is not actually illegal but will
- // help catch bugs.
- yyerror("cannot pass %+N as %T (... mismatch)", nl->n, tl);
+ if(nl != nil && nl->n->op == ONAME && nl->n->isddd && !isddd) {
+ // TODO(rsc): This is not actually illegal, but it will help catch bugs.
+ yyerror("to pass '%#N' as ...%T, use '%#N...'", nl->n, t->type, nl->n);
+ isddd = 1;
}
- if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
+ if(isddd) {
+ if(nl == nil)
+ goto notenough;
+ if(nl->next != nil)
+ goto toomany;
+ n = nl->n;
+ setlineno(n);
+ if(n->type != T)
+ nl->n = assignconv(n, t, desc);
goto out;
+ }
for(; nl; nl=nl->next) {
+ n = nl->n;
setlineno(nl->n);
- defaultlit(&nl->n, t->type);
- if(assignop(nl->n->type, t->type, &why) == 0)
- yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why);
+ if(n->type != T)
+ nl->n = assignconv(n, t->type, desc);
}
goto out;
}
- if(nl == nil) {
- yyerror("not enough arguments to %#O", op);
- goto out;
- }
+ if(nl == nil)
+ goto notenough;
n = nl->n;
- setlineno(nl->n);
+ setlineno(n);
if(n->type != T)
nl->n = assignconv(n, t, desc);
nl = nl->next;
}
- if(nl != nil) {
- yyerror("too many arguments to %#O", op);
- goto out;
- }
+ if(nl != nil)
+ goto toomany;
+ if(isddd)
+ yyerror("invalid use of ... in %#O", op);
out:
lineno = lno;
+ return;
+
+notenough:
+ yyerror("not enough arguments to %#O", op);
+ goto out;
+
+toomany:
+ yyerror("too many arguments to %#O", op);
+ goto out;
}
/*
@@ -1658,23 +1814,103 @@ indexdup(Node *n, Node *hash[], ulong nhash)
hash[h] = n;
}
+static int
+prime(ulong h, ulong sr)
+{
+ ulong n;
+
+ for(n=3; n<=sr; n+=2)
+ if(h%n == 0)
+ return 0;
+ return 1;
+}
+
+static ulong
+inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
+{
+ ulong h, sr;
+ NodeList *ll;
+ int i;
+
+ // count the number of entries
+ h = 0;
+ for(ll=n->list; ll; ll=ll->next)
+ h++;
+
+ // if the auto hash table is
+ // large enough use it.
+ if(h <= nautohash) {
+ *hash = autohash;
+ memset(*hash, 0, nautohash * sizeof(**hash));
+ return nautohash;
+ }
+
+ // make hash size odd and 12% larger than entries
+ h += h/8;
+ h |= 1;
+
+ // calculate sqrt of h
+ sr = h/2;
+ for(i=0; i<5; i++)
+ sr = (sr + h/sr)/2;
+
+ // check for primeality
+ while(!prime(h, sr))
+ h += 2;
+
+ // build and return a throw-away hash table
+ *hash = mal(h * sizeof(**hash));
+ memset(*hash, 0, h * sizeof(**hash));
+ return h;
+}
+
static void
typecheckcomplit(Node **np)
{
int bad, i, len, nerr;
- Node *l, *n, *hash[101];
+ Node *l, *n, **hash;
NodeList *ll;
- Type *t, *f;
+ Type *t, *f, *pushtype;
Sym *s;
+ int32 lno;
+ ulong nhash;
+ Node *autohash[101];
n = *np;
+ lno = lineno;
- memset(hash, 0, sizeof hash);
+ if(n->right == N) {
+ if(n->list != nil)
+ setlineno(n->list->n);
+ yyerror("missing type in composite literal");
+ goto error;
+ }
+ setlineno(n->right);
l = typecheck(&n->right /* sic */, Etype);
if((t = l->type) == T)
goto error;
nerr = nerrors;
+
+ // can omit type on composite literal values if the outer
+ // composite literal is array, slice, or map, and the
+ // element type is itself a struct, array, slice, or map.
+ pushtype = T;
+ if(t->etype == TARRAY || t->etype == TMAP) {
+ pushtype = t->type;
+ if(pushtype != T) {
+ switch(pushtype->etype) {
+ case TSTRUCT:
+ case TARRAY:
+ case TMAP:
+ break;
+ default:
+ pushtype = T;
+ break;
+ }
+ }
+ }
+
switch(t->etype) {
default:
yyerror("invalid type for composite literal: %T", t);
@@ -1682,31 +1918,29 @@ typecheckcomplit(Node **np)
break;
case TARRAY:
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
len = 0;
i = 0;
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
- if(l->op == OKEY) {
- typecheck(&l->left, Erv);
- evconst(l->left);
- i = nonnegconst(l->left);
- if(i < 0) {
- yyerror("array index must be non-negative integer constant");
- i = -(1<<30); // stay negative for a while
- }
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "array index");
- } else {
- typecheck(&ll->n, Erv);
- defaultlit(&ll->n, t->type);
- ll->n = assignconv(ll->n, t->type, "array index");
- ll->n = nod(OKEY, nodintconst(i), ll->n);
- ll->n->left->type = types[TINT];
- ll->n->left->typecheck = 1;
+ setlineno(l);
+ if(l->op != OKEY) {
+ l = nod(OKEY, nodintconst(i), l);
+ l->left->type = types[TINT];
+ l->left->typecheck = 1;
+ ll->n = l;
+ }
+
+ typecheck(&l->left, Erv);
+ evconst(l->left);
+ i = nonnegconst(l->left);
+ if(i < 0) {
+ yyerror("array index must be non-negative integer constant");
+ i = -(1<<30); // stay negative for a while
}
if(i >= 0)
- indexdup(ll->n->left, hash, nelem(hash));
+ indexdup(l->left, hash, nhash);
i++;
if(i > len) {
len = i;
@@ -1716,6 +1950,12 @@ typecheckcomplit(Node **np)
t->bound = -1; // no more errors
}
}
+
+ if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
+ l->right->right = typenod(pushtype);
+ typecheck(&l->right, Erv);
+ defaultlit(&l->right, t->type);
+ l->right = assignconv(l->right, t->type, "array index");
}
if(t->bound == -100)
t->bound = len;
@@ -1725,20 +1965,27 @@ typecheckcomplit(Node **np)
break;
case TMAP:
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
+ setlineno(l);
if(l->op != OKEY) {
typecheck(&ll->n, Erv);
yyerror("missing key in map literal");
continue;
}
+
typecheck(&l->left, Erv);
- typecheck(&l->right, Erv);
defaultlit(&l->left, t->down);
- defaultlit(&l->right, t->type);
l->left = assignconv(l->left, t->down, "map key");
+ keydup(l->left, hash, nhash);
+
+ if(l->right->op == OCOMPLIT && l->right->right == N && pushtype != T)
+ l->right->right = typenod(pushtype);
+ typecheck(&l->right, Erv);
+ defaultlit(&l->right, t->type);
l->right = assignconv(l->right, t->type, "map value");
- keydup(l->left, hash, nelem(hash));
}
n->op = OMAPLIT;
break;
@@ -1749,6 +1996,7 @@ typecheckcomplit(Node **np)
// simple list of variables
f = t->type;
for(ll=n->list; ll; ll=ll->next) {
+ setlineno(ll->n);
typecheck(&ll->n, Erv);
if(f == nil) {
if(!bad++)
@@ -1766,9 +2014,12 @@ typecheckcomplit(Node **np)
if(f != nil)
yyerror("too few values in struct initializer");
} else {
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
// keyed list
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
+ setlineno(l);
if(l->op != OKEY) {
if(!bad++)
yyerror("mixture of field:value and value initializers");
@@ -1781,6 +2032,11 @@ typecheckcomplit(Node **np)
typecheck(&l->right, Erv);
continue;
}
+ // Sym might have resolved to name in other top-level
+ // package, because of import dot. Redirect to correct sym
+ // before we do the lookup.
+ if(s->pkg != localpkg)
+ s = lookup(s->name);
l->left = newname(s);
l->left->typecheck = 1;
f = lookdot1(s, t, t->type, 0);
@@ -1790,7 +2046,7 @@ typecheckcomplit(Node **np)
continue;
}
s = f->sym;
- fielddup(newname(s), hash, nelem(hash));
+ fielddup(newname(s), hash, nhash);
l->right = assignconv(l->right, f->type, "field value");
}
}
@@ -1802,11 +2058,13 @@ typecheckcomplit(Node **np)
n->type = t;
*np = n;
+ lineno = lno;
return;
error:
n->type = T;
*np = n;
+ lineno = lno;
}
/*
@@ -1890,6 +2148,8 @@ islvalue(Node *n)
case OINDEX:
if(isfixedarray(n->left->type))
return islvalue(n->left);
+ if(n->left->type != T && n->left->type->etype == TSTRING)
+ return 0;
// fall through
case OIND:
case ODOTPTR:
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index dbf6f708a..33f375631 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -11,13 +11,18 @@
* rewrite with a constant
*/
Node*
-unsafenmagic(Node *fn, NodeList *args)
+unsafenmagic(Node *nn)
{
Node *r, *n;
Sym *s;
Type *t, *tr;
long v;
Val val;
+ Node *fn;
+ NodeList *args;
+
+ fn = nn->left;
+ args = nn->list;
if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
goto no;
@@ -35,13 +40,14 @@ unsafenmagic(Node *fn, NodeList *args)
defaultlit(&r, T);
tr = r->type;
if(tr == T)
- goto no;
+ goto bad;
v = tr->width;
goto yes;
}
if(strcmp(s->name, "Offsetof") == 0) {
+ typecheck(&r, Erv);
if(r->op != ODOT && r->op != ODOTPTR)
- goto no;
+ goto bad;
typecheck(&r, Erv);
v = r->xoffset;
goto yes;
@@ -51,7 +57,7 @@ unsafenmagic(Node *fn, NodeList *args)
defaultlit(&r, T);
tr = r->type;
if(tr == T)
- goto no;
+ goto bad;
// make struct { byte; T; }
t = typ(TSTRUCT);
@@ -70,9 +76,15 @@ unsafenmagic(Node *fn, NodeList *args)
no:
return N;
+bad:
+ yyerror("invalid expression %#N", nn);
+ v = 0;
+ goto ret;
+
yes:
if(args->next != nil)
yyerror("extra arguments for %S", s);
+ret:
// any side effects disappear; ignore init
val.ctype = CTINT;
val.u.xval = mal(sizeof(*n->val.u.xval));
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 4f59d5598..fa3e5d5e4 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -11,12 +11,14 @@ static Node* makenewvar(Type*, NodeList**, Node**);
static Node* ascompatee1(int, Node*, Node*, NodeList**);
static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**);
static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**);
-static NodeList* ascompatte(int, Type**, NodeList*, int, NodeList**);
+static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**);
static Node* convas(Node*, NodeList**);
static void heapmoves(void);
static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
+static Node* addstr(Node*, NodeList**);
+static Node* append(Node*, NodeList**);
static NodeList* walkdefstack;
@@ -134,6 +136,10 @@ walkdeftype(Node *n)
n->diag = 1;
goto ret;
}
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
// copy new type and clear fields
// that don't come along
@@ -257,6 +263,10 @@ walkdef(Node *n)
yyerror("const initializer must be constant");
goto ret;
}
+ if(isconst(e, CTNIL)) {
+ yyerror("const initializer cannot be nil");
+ goto ret;
+ }
t = n->type;
if(t != T) {
convlit(&e, t);
@@ -281,6 +291,13 @@ walkdef(Node *n)
if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
+ if(nerrors > 0) {
+ // Can have undefined variables in x := foo
+ // that make x have an n->ndefn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break;
+ }
fatal("var without type, init: %S", n->sym);
}
if(n->defn->op == ONAME) {
@@ -292,10 +309,14 @@ walkdef(Node *n)
break;
case OTYPE:
+ if(curfn)
+ defercheckwidth();
n->walkdef = 1;
n->type = typ(TFORW);
n->type->sym = n->sym;
walkdeftype(n);
+ if(curfn)
+ resumecheckwidth();
break;
case OPACK:
@@ -354,7 +375,7 @@ walkstmt(Node **np)
NodeList *init;
NodeList *ll, *rl;
int cl, lno;
- Node *n;
+ Node *n, *f;
n = *np;
if(n == N)
@@ -481,11 +502,19 @@ walkstmt(Node **np)
n->list = nil;
break;
}
+ if(count(n->list) == 1 && count(rl) > 1) {
+ // OAS2FUNC in disguise
+ f = n->list->n;
+ if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
+ fatal("expected return of call, have %#N", f);
+ n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
+ break;
+ }
ll = ascompatee(n->op, rl, n->list, &n->ninit);
n->list = reorder3(ll);
break;
}
- ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
+ ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = ll;
break;
@@ -542,6 +571,7 @@ walkexpr(Node **np, NodeList **init)
NodeList *ll, *lr, *lpost;
Type *t;
int et;
+ int64 v, v1, v2, len;
int32 lno;
Node *n, *fn;
char buf[100], *p;
@@ -594,8 +624,6 @@ walkexpr(Node **np, NodeList **init)
case OMINUS:
case OPLUS:
case OCOM:
- case OLEN:
- case OCAP:
case OREAL:
case OIMAG:
case ODOT:
@@ -606,13 +634,27 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
goto ret;
+ case OLEN:
+ case OCAP:
+ walkexpr(&n->left, init);
+
+ // replace len(*[10]int) with 10.
+ // delayed until now to preserve side effects.
+ t = n->left->type;
+ if(isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t)) {
+ safeexpr(n->left, init);
+ nodconst(n, n->type, t->bound);
+ n->typecheck = 1;
+ }
+ goto ret;
+
case OLSH:
case ORSH:
case OAND:
case OOR:
case OXOR:
- case OANDAND:
- case OOROR:
case OSUB:
case OMUL:
case OEQ:
@@ -626,6 +668,17 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
+
+ case OANDAND:
+ case OOROR:
+ walkexpr(&n->left, init);
+ // cannot put side effects from n->right on init,
+ // because they cannot run before n->left is checked.
+ // save elsewhere and store on the eventual n->right.
+ ll = nil;
+ walkexpr(&n->right, &ll);
+ n->right->ninit = concat(n->right->ninit, ll);
+ goto ret;
case OPRINT:
case OPRINTN:
@@ -656,7 +709,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -666,7 +719,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
if(isselect(n)) {
// special prob with selectsend and selectrecv:
@@ -676,7 +729,7 @@ walkexpr(Node **np, NodeList **init)
Node *b;
b = nodbool(0);
typecheck(&b, Erv);
- lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
+ lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init);
n->list = concat(n->list, lr);
}
goto ret;
@@ -687,8 +740,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
- lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, init);
+ ll = ascompatte(n->op, 0, getthis(t), list1(n->left->left), 0, init);
+ lr = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
ll = concat(ll, lr);
n->left->left = N;
ullmancalc(n->left);
@@ -882,43 +935,55 @@ walkexpr(Node **np, NodeList **init)
case OCONV:
case OCONVNOP:
if(thechar == '5') {
- if(isfloat[n->left->type->etype] &&
- (n->type->etype == TINT64 || n->type->etype == TUINT64)) {
- n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
+ if(isfloat[n->left->type->etype]) {
+ if(n->type->etype == TINT64) {
+ n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
+ goto ret;
+ }
+ if(n->type->etype == TUINT64) {
+ n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
+ goto ret;
+ }
}
- if((n->left->type->etype == TINT64 || n->left->type->etype == TUINT64) &&
- isfloat[n->type->etype]) {
- n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
- goto ret;
+ if(isfloat[n->type->etype]) {
+ if(n->left->type->etype == TINT64) {
+ n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
+ goto ret;
+ }
+ if(n->left->type->etype == TUINT64) {
+ n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
+ goto ret;
+ }
}
}
walkexpr(&n->left, init);
goto ret;
case OASOP:
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
if(n->etype == OANDNOT) {
n->etype = OAND;
n->right = nod(OCOM, n->right, N);
typecheck(&n->right, Erv);
}
+ n->left = safeexpr(n->left, init);
+ walkexpr(&n->left, init);
+ l = n->left;
+ walkexpr(&n->right, init);
/*
* on 32-bit arch, rewrite 64-bit ops into l = l op r.
* on 386, rewrite float ops into l = l op r.
* everywhere, rewrite map ops into l = l op r.
* everywhere, rewrite string += into l = l op r.
+ * everywhere, rewrite complex /= into l = l op r.
* TODO(rsc): Maybe this rewrite should be done always?
*/
et = n->left->type->etype;
if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
(thechar == '8' && isfloat[et]) ||
l->op == OINDEXMAP ||
- et == TSTRING) {
+ et == TSTRING ||
+ (iscomplex[et] && n->etype == ODIV)) {
l = safeexpr(n->left, init);
a = l;
if(a->op == OINDEXMAP) {
@@ -952,9 +1017,11 @@ walkexpr(Node **np, NodeList **init)
*/
et = n->left->type->etype;
if(iscomplex[et] && n->op == ODIV) {
- n = mkcall("complex128div", n->type, init,
+ t = n->type;
+ n = mkcall("complex128div", types[TCOMPLEX128], init,
conv(n->left, types[TCOMPLEX128]),
conv(n->right, types[TCOMPLEX128]));
+ n = conv(n, t);
goto ret;
}
/*
@@ -981,11 +1048,36 @@ walkexpr(Node **np, NodeList **init)
// if range of type cannot exceed static array bound,
// disable bounds check
- if(!isslice(n->left->type))
+ if(isfixedarray(n->left->type))
if(n->right->type->width < 4)
if((1<<(8*n->right->type->width)) <= n->left->type->bound)
n->etype = 1;
+ if(isconst(n->left, CTSTR))
+ if(n->right->type->width < 4)
+ if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len)
+ n->etype = 1;
+
+ // check for static out of bounds
+ if(isconst(n->right, CTINT) && !n->etype) {
+ v = mpgetfix(n->right->val.u.xval);
+ len = 1LL<<60;
+ t = n->left->type;
+ if(isconst(n->left, CTSTR))
+ len = n->left->val.u.sval->len;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t))
+ len = t->bound;
+ if(v < 0 || v >= (1LL<<31) || v >= len)
+ yyerror("index out of bounds");
+ else if(isconst(n->left, CTSTR)) {
+ // replace "abc"[2] with 'b'.
+ // delayed until now because "abc"[2] is not
+ // an ideal constant.
+ nodconst(n, n->type, n->left->val.u.sval->s[v]);
+ }
+ }
goto ret;
case OINDEXMAP:
@@ -1002,24 +1094,61 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSLICE:
+ case OSLICEARR:
walkexpr(&n->left, init);
n->left = safeexpr(n->left, init);
walkexpr(&n->right->left, init);
n->right->left = safeexpr(n->right->left, init);
walkexpr(&n->right->right, init);
n->right->right = safeexpr(n->right->right, init);
+
+ len = 1LL<<60;
+ t = n->left->type;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t))
+ len = t->bound;
+
+ // check for static out of bounds
+ // NOTE: v > len not v >= len.
+ v1 = -1;
+ v2 = -1;
+ if(isconst(n->right->left, CTINT)) {
+ v1 = mpgetfix(n->right->left->val.u.xval);
+ if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
+ yyerror("slice index out of bounds");
+ v1 = -1;
+ }
+ }
+ if(isconst(n->right->right, CTINT)) {
+ v2 = mpgetfix(n->right->right->val.u.xval);
+ if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
+ yyerror("slice index out of bounds");
+ v2 = -1;
+ }
+ }
+ if(v1 >= 0 && v2 >= 0 && v1 > v2)
+ yyerror("inverted slice range");
+
+ if(n->op == OSLICEARR)
+ goto slicearray;
+
// dynamic slice
- // sliceslice(old []any, lb int, hb int, width int) (ary []any)
- // sliceslice1(old []any, lb int, width int) (ary []any)
+ // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
+ // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
t = n->type;
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TUINT64]);
if(n->right->right != N) {
fn = syslook("sliceslice", 1);
argtype(fn, t->type); // any-1
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
n->left,
- conv(n->right->left, types[TINT]),
- conv(n->right->right, types[TINT]),
+ l,
+ conv(n->right->right, types[TUINT64]),
nodintconst(t->type->width));
} else {
fn = syslook("sliceslice1", 1);
@@ -1027,47 +1156,33 @@ walkexpr(Node **np, NodeList **init)
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
n->left,
- conv(n->right->left, types[TINT]),
+ l,
nodintconst(t->type->width));
}
goto ret;
- case OSLICEARR:
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right, init);
- n->right->right = safeexpr(n->right->right, init);
+ slicearray:
// static slice
- // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
+ // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
t = n->type;
fn = syslook("slicearray", 1);
- argtype(fn, n->left->type); // any-1
+ argtype(fn, n->left->type->type); // any-1
argtype(fn, t->type); // any-2
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TUINT64]);
if(n->right->right == N)
- r = nodintconst(n->left->type->bound);
+ r = nodintconst(n->left->type->type->bound);
else
- r = conv(n->right->right, types[TINT]);
+ r = conv(n->right->right, types[TUINT64]);
n = mkcall1(fn, t, init,
- nod(OADDR, n->left, N), nodintconst(n->left->type->bound),
- conv(n->right->left, types[TINT]),
+ n->left, nodintconst(n->left->type->type->bound),
+ l,
r,
nodintconst(t->type->width));
goto ret;
- case OCONVSLICE:
- // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
- fn = syslook("slicearray", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, n->type->type); // any-2
- n = mkcall1(fn, n->type, init, n->left,
- nodintconst(n->left->type->type->bound),
- nodintconst(0),
- nodintconst(n->left->type->type->bound),
- nodintconst(n->type->type->width));
- goto ret;
-
case OADDR:;
Node *nvar, *nstar;
@@ -1118,46 +1233,62 @@ walkexpr(Node **np, NodeList **init)
goto ret;
}
+ // prepare for rewrite below
+ if(n->etype == OEQ || n->etype == ONE) {
+ n->left = cheapexpr(n->left, init);
+ n->right = cheapexpr(n->right, init);
+ }
+
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->etype, r, nodintconst(0));
+
+ // quick check of len before full compare for == or !=
+ if(n->etype == OEQ || n->etype == ONE) {
+ if(n->etype == OEQ)
+ r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ else
+ r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ typecheck(&r, Erv);
+ walkexpr(&r, nil);
+ }
typecheck(&r, Erv);
n = r;
goto ret;
case OADDSTR:
- // sys_catstring(s1, s2)
- n = mkcall("catstring", n->type, init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
+ n = addstr(n, init);
goto ret;
case OSLICESTR:
// sys_slicestring(s, lb, hb)
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TINT]);
if(n->right->right) {
n = mkcall("slicestring", n->type, init,
conv(n->left, types[TSTRING]),
- conv(n->right->left, types[TINT]),
+ l,
conv(n->right->right, types[TINT]));
} else {
n = mkcall("slicestring1", n->type, init,
conv(n->left, types[TSTRING]),
- conv(n->right->left, types[TINT]));
+ l);
}
goto ret;
-
- case OINDEXSTR:
- // TODO(rsc): should be done in back end
- // sys_indexstring(s, i)
- n = mkcall("indexstring", n->type, init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TINT]));
+
+ case OAPPEND:
+ n = append(n, init);
goto ret;
case OCOPY:
- fn = syslook("slicecopy", 1);
+ if(n->right->type->etype == TSTRING)
+ fn = syslook("slicestringcopy", 1);
+ else
+ fn = syslook("slicecopy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
n = mkcall1(fn, n->type, init,
@@ -1441,47 +1572,51 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
/*
* helpers for shape errors
*/
-static void
+static char*
dumptypes(Type **nl, char *what)
{
int first;
Type *l;
Iter savel;
+ Fmt fmt;
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
l = structfirst(&savel, nl);
- print("\t");
first = 1;
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
if(first)
first = 0;
else
- print(", ");
- print("%T", l);
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", l);
}
if(first)
- print("[no arguments %s]", what);
- print("\n");
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
}
-static void
+static char*
dumpnodetypes(NodeList *l, char *what)
{
int first;
Node *r;
+ Fmt fmt;
- print("\t");
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
first = 1;
for(; l; l=l->next) {
r = l->n;
if(first)
first = 0;
else
- print(", ");
- print("%T", r->type);
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", r->type);
}
if(first)
- print("[no arguments %s]", what);
- print("\n");
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
}
/*
@@ -1491,12 +1626,13 @@ dumpnodetypes(NodeList *l, char *what)
* func(expr-list)
*/
static NodeList*
-ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
+ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
Iter savel;
+ char *l1, *l2;
lr0 = lr;
l = structfirst(&savel, nl);
@@ -1545,7 +1681,7 @@ loop:
// only if we are assigning a single ddd
// argument to a ddd parameter then it is
// passed thru unencapsulated
- if(r != N && lr->next == nil && r->isddd && eqtype(l->type, r->type)) {
+ if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
@@ -1561,12 +1697,12 @@ loop:
if(l == T || r == N) {
if(l != T || r != N) {
+ l1 = dumptypes(nl, "expected");
+ l2 = dumpnodetypes(lr0, "given");
if(l != T)
- yyerror("not enough arguments to %O", op);
+ yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
else
- yyerror("too many arguments to %O", op);
- dumptypes(nl, "expected");
- dumpnodetypes(lr0, "given");
+ yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
}
goto ret;
}
@@ -1740,7 +1876,7 @@ walkprint(Node *nn, NodeList **init, int defer)
if(defer) {
if(op == OPRINTN)
fmtprint(&fmt, "\n");
- on = syslook("printf", 1);
+ on = syslook("goprintf", 1);
on->type = functype(nil, intypes, nil);
args->n = nod(OLITERAL, N, N);
args->n->val.ctype = CTSTR;
@@ -1769,7 +1905,7 @@ callnew(Type *t)
Node *fn;
dowidth(t);
- fn = syslook("mal", 1);
+ fn = syslook("new", 1);
argtype(fn, t);
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
}
@@ -2046,12 +2182,17 @@ static void
heapmoves(void)
{
NodeList *nn;
-
+ int32 lno;
+
+ lno = lineno;
+ lineno = curfn->lineno;
nn = paramstoheap(getthis(curfn->type), 0);
nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
curfn->enter = concat(curfn->enter, nn);
+ lineno = curfn->endlineno;
curfn->exit = returnsfromheap(getoutarg(curfn->type));
+ lineno = lno;
}
static Node*
@@ -2143,3 +2284,83 @@ mapfn(char *name, Type *t)
argtype(fn, t->type);
return fn;
}
+
+static Node*
+addstr(Node *n, NodeList **init)
+{
+ Node *r, *cat, *typstr;
+ NodeList *in, *args;
+ int i, count;
+
+ count = 0;
+ for(r=n; r->op == OADDSTR; r=r->left)
+ count++; // r->right
+ count++; // r
+
+ // prepare call of runtime.catstring of type int, string, string, string
+ // with as many strings as we have.
+ cat = syslook("concatstring", 1);
+ cat->type = T;
+ cat->ntype = nod(OTFUNC, N, N);
+ in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
+ typstr = typenod(types[TSTRING]);
+ for(i=0; i<count; i++)
+ in = list(in, nod(ODCLFIELD, N, typstr));
+ cat->ntype->list = in;
+ cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
+
+ args = nil;
+ for(r=n; r->op == OADDSTR; r=r->left)
+ args = concat(list1(conv(r->right, types[TSTRING])), args);
+ args = concat(list1(conv(r, types[TSTRING])), args);
+ args = concat(list1(nodintconst(count)), args);
+
+ r = nod(OCALL, cat, N);
+ r->list = args;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ r->type = n->type;
+
+ return r;
+}
+
+static Node*
+append(Node *n, NodeList **init)
+{
+ int i, j;
+ Node *f, *r;
+ NodeList *in, *args;
+
+ if(n->isddd) {
+ f = syslook("appendslice", 1);
+ argtype(f, n->type);
+ argtype(f, n->type->type);
+ argtype(f, n->type);
+ r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
+ return r;
+ }
+
+ j = count(n->list) - 1;
+ f = syslook("append", 1);
+ f->type = T;
+ f->ntype = nod(OTFUNC, N, N);
+ in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type
+ in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count
+ in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice
+ for(i=0; i<j; i++)
+ in = list(in, nod(ODCLFIELD, N, typenod(n->type->type)));
+ f->ntype->list = in;
+ f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type)));
+
+ args = list1(typename(n->type));
+ args = list(args, nodintconst(j));
+ args = concat(args, n->list);
+
+ r = nod(OCALL, f, N);
+ r->list = args;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ r->type = n->type;
+
+ return r;
+}
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
index 49244f152..b5c76fb0f 100644
--- a/src/cmd/godefs/Makefile
+++ b/src/cmd/godefs/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
TARG=godefs
OFILES=\
@@ -12,13 +13,4 @@ OFILES=\
HFILES=a.h
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
index 6ff542f48..69ee1be5d 100644
--- a/src/cmd/godefs/main.c
+++ b/src/cmd/godefs/main.c
@@ -82,7 +82,7 @@
#include "a.h"
-#ifdef __MINGW32__
+#ifdef _WIN32
int
spawn(char *prog, char **argv)
{
@@ -133,7 +133,7 @@ Lang go =
"type %s struct {\n",
"type %s struct {\n",
- "\tPad%d [%d]byte;\n",
+ "\tPad_godefs_%d [%d]byte;\n",
"}\n",
gotypefmt,
@@ -150,7 +150,7 @@ Lang c =
"typedef struct %s %s;\nstruct %s {\n",
"typedef union %s %s;\nunion %s {\n",
- "\tbyte pad%d[%d];\n",
+ "\tbyte pad_godefs_%d[%d];\n",
"};\n",
ctypefmt,
@@ -373,6 +373,8 @@ Continue:
prefix = prefixlen(t);
for(j=0; j<t->nf; j++) {
f = &t->f[j];
+ if(f->type->kind == 0)
+ continue;
// padding
if(t->kind == Struct || lang == &go) {
if(f->offset%8 != 0 || f->size%8 != 0) {
@@ -391,7 +393,7 @@ Continue:
if(cutprefix(name))
name += prefix;
if(strcmp(name, "") == 0) {
- snprint(nambuf, sizeof nambuf, "Pad%d", npad++);
+ snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++);
name = nambuf;
}
Bprint(bout, "\t%#lT;\n", name, f->type);
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
index 8d3be1913..1bc96d4c8 100644
--- a/src/cmd/godefs/stabs.c
+++ b/src/cmd/godefs/stabs.c
@@ -363,13 +363,22 @@ parsedef(char **pp, char *name)
return nil;
}
+ while(f->type->kind == Typedef)
+ f->type = f->type->type;
+ if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
+ // unknown type but <= 64 bits and bit size is a power of two.
+ // could be enum - make Uint64 and then let it reduce
+ tt = emalloc(sizeof *tt);
+ *tt = *f->type;
+ f->type = tt;
+ tt->kind = Uint64;
+ }
+
// rewrite
// uint32 x : 8;
// into
// uint8 x;
// hooray for bitfields.
- while(f->type->kind == Typedef)
- f->type = f->type->type;
while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
tt = emalloc(sizeof *tt);
*tt = *f->type;
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
index d799219dd..c4e0fd9f9 100644
--- a/src/cmd/godoc/Makefile
+++ b/src/cmd/godoc/Makefile
@@ -2,16 +2,19 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=godoc
GOFILES=\
codewalk.go\
+ dirtrees.go\
+ format.go\
godoc.go\
index.go\
main.go\
mapping.go\
snippet.go\
spec.go\
+ utils.go\
include ../../Make.cmd
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 806849c00..bda63a9f6 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -31,26 +31,26 @@ import (
// Handler for /doc/codewalk/ and below.
-func codewalk(c *http.Conn, r *http.Request) {
+func codewalk(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[len("/doc/codewalk/"):]
abspath := absolutePath(r.URL.Path[1:], *goroot)
r.ParseForm()
if f := r.FormValue("fileprint"); f != "" {
- codewalkFileprint(c, r, f)
+ codewalkFileprint(w, r, f)
return
}
// If directory exists, serve list of code walks.
dir, err := os.Lstat(abspath)
if err == nil && dir.IsDirectory() {
- codewalkDir(c, r, relpath, abspath)
+ codewalkDir(w, r, relpath, abspath)
return
}
// If file exists, serve using standard file server.
if err == nil {
- serveFile(c, r)
+ serveFile(w, r)
return
}
@@ -58,18 +58,18 @@ func codewalk(c *http.Conn, r *http.Request) {
// a codewalk description.
cw, err := loadCodewalk(abspath + ".xml")
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
// Canonicalize the path and redirect if changed
- if redirect(c, r) {
+ if redirect(w, r) {
return
}
b := applyTemplate(codewalkHTML, "codewalk", cw)
- servePage(c, "Codewalk: "+cw.Title, "", "", b)
+ servePage(w, "Codewalk: "+cw.Title, "", "", b)
}
@@ -178,7 +178,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
// codewalkDir serves the codewalk directory listing.
// It scans the directory for subdirectories or files named *.xml
// and prepares a table.
-func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
+func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
type elem struct {
Name string
Title string
@@ -186,8 +186,8 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
dir, err := ioutil.ReadDir(abspath)
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
var v vector.Vector
@@ -204,7 +204,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
}
b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
- servePage(c, "Codewalks", "", "", b)
+ servePage(w, "Codewalks", "", "", b)
}
@@ -214,11 +214,12 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
// in the response. This format is used for the middle window pane
// of the codewalk pages. It is a separate iframe and does not get
// the usual godoc HTML wrapper.
-func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
+func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
abspath := absolutePath(f, *goroot)
data, err := ioutil.ReadFile(abspath)
if err != nil {
- serveError(c, r, f, err)
+ log.Print(err)
+ serveError(w, r, f, err)
return
}
lo, _ := strconv.Atoi(r.FormValue("lo"))
@@ -242,17 +243,17 @@ func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
}
}
- io.WriteString(c, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
- template.HTMLEscape(c, data[0:mark])
- io.WriteString(c, "<a name='mark'></a>")
- template.HTMLEscape(c, data[mark:lo])
+ io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
+ template.HTMLEscape(w, data[0:mark])
+ io.WriteString(w, "<a name='mark'></a>")
+ template.HTMLEscape(w, data[mark:lo])
if lo < hi {
- io.WriteString(c, "<div class='codewalkhighlight'>")
- template.HTMLEscape(c, data[lo:hi])
- io.WriteString(c, "</div>")
+ io.WriteString(w, "<div class='codewalkhighlight'>")
+ template.HTMLEscape(w, data[lo:hi])
+ io.WriteString(w, "</div>")
}
- template.HTMLEscape(c, data[hi:])
- io.WriteString(c, "</pre>")
+ template.HTMLEscape(w, data[hi:])
+ io.WriteString(w, "</pre>")
}
@@ -450,13 +451,13 @@ func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os
// through file, but that seems like overkill.
return 0, 0, os.NewError("reverse search not implemented")
}
- m := re.Execute(data[hi:])
+ m := re.FindIndex(data[hi:])
if len(m) > 0 {
m[0] += hi
m[1] += hi
} else if hi > 0 {
// No match. Wrap to beginning of data.
- m = re.Execute(data)
+ m = re.FindIndex(data)
}
if len(m) == 0 {
return 0, 0, os.NewError("no match for " + pattern)
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
new file mode 100644
index 000000000..edb4a169d
--- /dev/null
+++ b/src/cmd/godoc/dirtrees.go
@@ -0,0 +1,341 @@
+// 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.
+
+// This file contains the code dealing with package directory trees.
+
+package main
+
+import (
+ "bytes"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ pathutil "path"
+ "strings"
+ "unicode"
+)
+
+
+type Directory struct {
+ Depth int
+ Path string // includes Name
+ Name string
+ Text string // package documentation, if any
+ Dirs []*Directory // subdirectories
+}
+
+
+func isGoFile(f *os.FileInfo) bool {
+ return f.IsRegular() &&
+ !strings.HasPrefix(f.Name, ".") && // ignore .files
+ pathutil.Ext(f.Name) == ".go"
+}
+
+
+func isPkgFile(f *os.FileInfo) bool {
+ return isGoFile(f) &&
+ !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+}
+
+
+func isPkgDir(f *os.FileInfo) bool {
+ return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
+}
+
+
+func firstSentence(s string) string {
+ i := -1 // index+1 of first terminator (punctuation ending a sentence)
+ j := -1 // index+1 of first terminator followed by white space
+ prev := 'A'
+ for k, ch := range s {
+ k1 := k + 1
+ if ch == '.' || ch == '!' || ch == '?' {
+ if i < 0 {
+ i = k1 // first terminator
+ }
+ if k1 < len(s) && s[k1] <= ' ' {
+ if j < 0 {
+ j = k1 // first terminator followed by white space
+ }
+ if !unicode.IsUpper(prev) {
+ j = k1
+ break
+ }
+ }
+ }
+ prev = ch
+ }
+
+ if j < 0 {
+ // use the next best terminator
+ j = i
+ if j < 0 {
+ // no terminator at all, use the entire string
+ j = len(s)
+ }
+ }
+
+ return s[0:j]
+}
+
+
+type treeBuilder struct {
+ pathFilter func(string) bool
+ maxDepth int
+}
+
+
+func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
+ if b.pathFilter != nil && !b.pathFilter(path) {
+ return nil
+ }
+
+ if depth >= b.maxDepth {
+ // return a dummy directory so that the parent directory
+ // doesn't get discarded just because we reached the max
+ // directory depth
+ return &Directory{depth, path, name, "", nil}
+ }
+
+ list, _ := ioutil.ReadDir(path) // ignore errors
+
+ // determine number of subdirectories and if there are package files
+ ndirs := 0
+ hasPkgFiles := false
+ var synopses [4]string // prioritized package documentation (0 == highest priority)
+ for _, d := range list {
+ switch {
+ case isPkgDir(d):
+ ndirs++
+ case isPkgFile(d):
+ // looks like a package file, but may just be a file ending in ".go";
+ // don't just count it yet (otherwise we may end up with hasPkgFiles even
+ // though the directory doesn't contain any real package files - was bug)
+ if synopses[0] == "" {
+ // no "optimal" package synopsis yet; continue to collect synopses
+ file, err := parser.ParseFile(fset, pathutil.Join(path, d.Name), nil,
+ parser.ParseComments|parser.PackageClauseOnly)
+ if err == nil {
+ hasPkgFiles = true
+ if file.Doc != nil {
+ // prioritize documentation
+ i := -1
+ switch file.Name.Name {
+ case name:
+ i = 0 // normal case: directory name matches package name
+ case fakePkgName:
+ i = 1 // synopses for commands
+ case "main":
+ i = 2 // directory contains a main package
+ default:
+ i = 3 // none of the above
+ }
+ if 0 <= i && i < len(synopses) && synopses[i] == "" {
+ synopses[i] = firstSentence(doc.CommentText(file.Doc))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // create subdirectory tree
+ var dirs []*Directory
+ if ndirs > 0 {
+ dirs = make([]*Directory, ndirs)
+ i := 0
+ for _, d := range list {
+ if isPkgDir(d) {
+ dd := b.newDirTree(fset, pathutil.Join(path, d.Name), d.Name, depth+1)
+ if dd != nil {
+ dirs[i] = dd
+ i++
+ }
+ }
+ }
+ dirs = dirs[0:i]
+ }
+
+ // if there are no package files and no subdirectories
+ // containing package files, ignore the directory
+ if !hasPkgFiles && len(dirs) == 0 {
+ return nil
+ }
+
+ // select the highest-priority synopsis for the directory entry, if any
+ synopsis := ""
+ for _, synopsis = range synopses {
+ if synopsis != "" {
+ break
+ }
+ }
+
+ return &Directory{depth, path, name, synopsis, dirs}
+}
+
+
+// newDirectory creates a new package directory tree with at most maxDepth
+// levels, anchored at root. The result tree is pruned such that it only
+// contains directories that contain package files or that contain
+// subdirectories containing package files (transitively). If a non-nil
+// pathFilter is provided, directory paths additionally must be accepted
+// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
+// provided for maxDepth, nodes at larger depths are pruned as well; they
+// are assumed to contain package files even if their contents are not known
+// (i.e., in this case the tree may contain directories w/o any package files).
+//
+func newDirectory(root string, pathFilter func(string) bool, maxDepth int) *Directory {
+ d, err := os.Lstat(root)
+ if err != nil || !isPkgDir(d) {
+ return nil
+ }
+ if maxDepth < 0 {
+ maxDepth = 1e6 // "infinity"
+ }
+ b := treeBuilder{pathFilter, maxDepth}
+ // the file set provided is only for local parsing, no position
+ // information escapes and thus we don't need to save the set
+ return b.newDirTree(token.NewFileSet(), root, d.Name, 0)
+}
+
+
+func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
+ if dir != nil {
+ if len(dir.Dirs) == 0 {
+ buf.WriteString(dir.Path)
+ buf.WriteByte('\n')
+ return
+ }
+
+ for _, d := range dir.Dirs {
+ d.writeLeafs(buf)
+ }
+ }
+}
+
+
+func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
+ if dir != nil {
+ if !skipRoot {
+ c <- dir
+ }
+ for _, d := range dir.Dirs {
+ d.walk(c, false)
+ }
+ }
+}
+
+
+func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
+ c := make(chan *Directory)
+ go func() {
+ dir.walk(c, skipRoot)
+ close(c)
+ }()
+ return c
+}
+
+
+func (dir *Directory) lookupLocal(name string) *Directory {
+ for _, d := range dir.Dirs {
+ if d.Name == name {
+ return d
+ }
+ }
+ return nil
+}
+
+
+// lookup looks for the *Directory for a given path, relative to dir.
+func (dir *Directory) lookup(path string) *Directory {
+ d := strings.Split(dir.Path, "/", -1)
+ p := strings.Split(path, "/", -1)
+ i := 0
+ for i < len(d) {
+ if i >= len(p) || d[i] != p[i] {
+ return nil
+ }
+ i++
+ }
+ for dir != nil && i < len(p) {
+ dir = dir.lookupLocal(p[i])
+ i++
+ }
+ return dir
+}
+
+
+// DirEntry describes a directory entry. The Depth and Height values
+// are useful for presenting an entry in an indented fashion.
+//
+type DirEntry struct {
+ Depth int // >= 0
+ Height int // = DirList.MaxHeight - Depth, > 0
+ Path string // includes Name, relative to DirList root
+ Name string
+ Synopsis string
+}
+
+
+type DirList struct {
+ MaxHeight int // directory tree height, > 0
+ List []DirEntry
+}
+
+
+// listing creates a (linear) directory listing from a directory tree.
+// If skipRoot is set, the root directory itself is excluded from the list.
+//
+func (root *Directory) listing(skipRoot bool) *DirList {
+ if root == nil {
+ return nil
+ }
+
+ // determine number of entries n and maximum height
+ n := 0
+ minDepth := 1 << 30 // infinity
+ maxDepth := 0
+ for d := range root.iter(skipRoot) {
+ n++
+ if minDepth > d.Depth {
+ minDepth = d.Depth
+ }
+ if maxDepth < d.Depth {
+ maxDepth = d.Depth
+ }
+ }
+ maxHeight := maxDepth - minDepth + 1
+
+ if n == 0 {
+ return nil
+ }
+
+ // create list
+ list := make([]DirEntry, n)
+ i := 0
+ for d := range root.iter(skipRoot) {
+ p := &list[i]
+ p.Depth = d.Depth - minDepth
+ p.Height = maxHeight - p.Depth
+ // the path is relative to root.Path - remove the root.Path
+ // prefix (the prefix should always be present but avoid
+ // crashes and check)
+ path := d.Path
+ if strings.HasPrefix(d.Path, root.Path) {
+ path = d.Path[len(root.Path):]
+ }
+ // remove trailing '/' if any - path must be relative
+ if len(path) > 0 && path[0] == '/' {
+ path = path[1:]
+ }
+ p.Path = path
+ p.Name = d.Name
+ p.Synopsis = d.Text
+ i++
+ }
+
+ return &DirList{maxHeight, list}
+}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 955ed35bf..02779384c 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -24,7 +24,7 @@ godoc first tries localhost:6060 and then http://golang.org.
godoc -q Reader Writer
godoc -q math.Sin
- godoc -server=:6666 -q sin
+ godoc -server=:6060 -q sin
With the -http flag, it runs as a web server and presents the documentation as a
web page.
@@ -45,6 +45,10 @@ The flags are:
print (exported) source in command-line mode
-tabwidth=4
width of tabs in units of spaces
+ -timestamps=true
+ show timestamps with directory listings
+ -fulltext=false
+ build full text index for regular expression queries
-path=""
additional package directories (colon-separated)
-html
@@ -61,6 +65,10 @@ The flags are:
repository holding the source files.
-sync_minutes=0
sync interval in minutes; sync is disabled if <= 0
+ -filter=""
+ filter file containing permitted package directory paths
+ -filter_minutes=0
+ filter file update interval in minutes; update is disabled if <= 0
The -path flag accepts a list of colon-separated paths; unrooted paths are relative
to the current working directory. Each path is considered as an additional root for
@@ -76,6 +84,13 @@ as follows:
/home/bar/x -> bar/x
/public/x -> public/x
+Paths provided via -path may point to very large file systems that contain
+non-Go files. Creating the subtree of directories with Go packages may take
+a long amount of time. A file containing newline-separated directory paths
+may be provided with the -filter flag; if it exists, only directories
+on those paths are considered. If -filter_minutes is set, the filter_file is
+updated regularly by walking the entire directory tree.
+
When godoc runs as a web server, it creates a search index from all .go files
under -goroot (excluding files starting with .). The index is created at startup
and is automatically updated every time the -sync command terminates with exit
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
new file mode 100644
index 000000000..f68c67b24
--- /dev/null
+++ b/src/cmd/godoc/format.go
@@ -0,0 +1,342 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements FormatSelections and FormatText.
+// FormatText is used to HTML-format Go and non-Go source
+// text with line numbers and highlighted sections. It is
+// built on top of FormatSelections, a generic formatter
+// for "selected" text.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "io"
+ "regexp"
+ "strconv"
+ "template"
+)
+
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatSelections
+
+// A Selection is a function returning offset pairs []int{a, b}
+// describing consecutive non-overlapping text segments [a, b).
+// If there are no more segments, a Selection must return nil.
+//
+// TODO It's more efficient to return a pair (a, b int) instead
+// of creating lots of slices. Need to determine how to
+// indicate the end of a Selection.
+//
+type Selection func() []int
+
+
+// A LinkWriter writes some start or end "tag" to w for the text offset offs.
+// It is called by FormatSelections at the start or end of each link segment.
+//
+type LinkWriter func(w io.Writer, offs int, start bool)
+
+
+// A SegmentWriter formats a text according to selections and writes it to w.
+// The selections parameter is a bit set indicating which selections provided
+// to FormatSelections overlap with the text segment: If the n'th bit is set
+// in selections, the n'th selection provided to FormatSelections is overlapping
+// with the text.
+//
+type SegmentWriter func(w io.Writer, text []byte, selections int)
+
+
+// FormatSelections takes a text and writes it to w using link and segment
+// writers lw and sw as follows: lw is invoked for consecutive segment starts
+// and ends as specified through the links selection, and sw is invoked for
+// consecutive segments of text overlapped by the same selections as specified
+// by selections. The link writer lw may be nil, in which case the links
+// Selection is ignored.
+//
+func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, sw SegmentWriter, selections ...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
+ for {
+ // get the next segment change
+ index, offs, start := changes.next()
+ if index < 0 || offs > len(text) {
+ // no more segment changes or the next change
+ // is past the end of the text - we're done
+ break
+ }
+ // determine the kind of segment change
+ if index == len(selections)-1 {
+ // 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)
+ 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)
+ lastOffs = offs
+ mask := 1 << uint(index)
+ if start {
+ bitset |= mask
+ } else {
+ bitset &^= mask
+ }
+ }
+ }
+ sw(w, text[lastOffs:], bitset)
+}
+
+
+// A merger merges a slice of Selections and produces a sequence of
+// consecutive segment change events through repeated next() calls.
+//
+type merger struct {
+ selections []Selection
+ segments [][]int // segments[i] is the next segment of selections[i]
+}
+
+
+const infinity int = 2e9
+
+func newMerger(selections []Selection) *merger {
+ segments := make([][]int, len(selections))
+ for i, sel := range selections {
+ segments[i] = []int{infinity, infinity}
+ if sel != nil {
+ if seg := sel(); seg != nil {
+ segments[i] = seg
+ }
+ }
+ }
+ return &merger{selections, segments}
+}
+
+
+// next returns the next segment change: index specifies the Selection
+// to which the segment belongs, offs is the segment start or end offset
+// as determined by the start value. If there are no more segment changes,
+// next returns an index value < 0.
+//
+func (m *merger) next() (index, offs int, start bool) {
+ // find the next smallest offset where a segment starts or ends
+ offs = infinity
+ index = -1
+ for i, seg := range m.segments {
+ switch {
+ case seg[0] < offs:
+ offs = seg[0]
+ index = i
+ start = true
+ case seg[1] < offs:
+ offs = seg[1]
+ index = i
+ start = false
+ }
+ }
+ if index < 0 {
+ // no offset found => all selections merged
+ return
+ }
+ // offset found - it's either the start or end offset but
+ // either way it is ok to consume the start offset: set it
+ // to infinity so it won't be considered in the following
+ // next call
+ m.segments[index][0] = infinity
+ if start {
+ return
+ }
+ // end offset found - consume it
+ m.segments[index][1] = infinity
+ // advance to the next segment for that selection
+ seg := m.selections[index]()
+ if seg == nil {
+ return
+ }
+ m.segments[index] = seg
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatText
+
+// lineSelection returns the line segments for text as a Selection.
+func lineSelection(text []byte) Selection {
+ i, j := 0, 0
+ return func() (seg []int) {
+ // find next newline, if any
+ for j < len(text) {
+ j++
+ if text[j-1] == '\n' {
+ break
+ }
+ }
+ if i < j {
+ // text[i:j] constitutes a line
+ seg = []int{i, j}
+ i = j
+ }
+ return
+ }
+}
+
+
+// commentSelection returns the sequence of consecutive comments
+// in the Go src text as a Selection.
+//
+func commentSelection(src []byte) Selection {
+ var s scanner.Scanner
+ file := s.Init(token.NewFileSet(), "", src, nil, scanner.ScanComments+scanner.InsertSemis)
+ return func() (seg []int) {
+ for {
+ pos, tok, lit := s.Scan()
+ if tok == token.EOF {
+ break
+ }
+ offs := file.Offset(pos)
+ if tok == token.COMMENT {
+ seg = []int{offs, offs + len(lit)}
+ break
+ }
+ }
+ return
+ }
+}
+
+
+// makeSelection is a helper function to make a Selection from a slice of pairs.
+func makeSelection(matches [][]int) Selection {
+ return func() (seg []int) {
+ if len(matches) > 0 {
+ seg = matches[0]
+ matches = matches[1:]
+ }
+ return
+ }
+}
+
+
+// regexpSelection computes the Selection for the regular expression expr in text.
+func regexpSelection(text []byte, expr string) Selection {
+ var matches [][]int
+ if rx, err := regexp.Compile(expr); err == nil {
+ matches = rx.FindAllIndex(text, -1)
+ }
+ return makeSelection(matches)
+}
+
+
+var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
+
+// rangeSelection computes the Selection for a text range described
+// by the argument str; the range description must match the selRx
+// regular expression.
+//
+func rangeSelection(str string) Selection {
+ m := selRx.FindStringSubmatch(str)
+ if len(m) >= 2 {
+ from, _ := strconv.Atoi(m[1])
+ to, _ := strconv.Atoi(m[2])
+ if from < to {
+ return makeSelection([][]int{[]int{from, to}})
+ }
+ }
+ return nil
+}
+
+
+// Span tags for all the possible selection combinations that may
+// be generated by FormatText. Selections are indicated by a bitset,
+// and the value of the bitset specifies the tag to be used.
+//
+// bit 0: comments
+// bit 1: highlights
+// bit 2: selections
+//
+var startTags = [][]byte{
+ /* 000 */ []byte(``),
+ /* 001 */ []byte(`<span class ="comment">`),
+ /* 010 */ []byte(`<span class="highlight">`),
+ /* 011 */ []byte(`<span class="highlight-comment">`),
+ /* 100 */ []byte(`<span class="selection">`),
+ /* 101 */ []byte(`<span class="selection-comment">`),
+ /* 110 */ []byte(`<span class="selection-highlight">`),
+ /* 111 */ []byte(`<span class="selection-highlight-comment">`),
+}
+
+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
+ }
+ }
+ template.HTMLEscape(w, text)
+ }
+}
+
+
+// FormatText HTML-escapes text and returns it wrapped in <pre> tags.
+// Conscutive text segments are wrapped in HTML spans (with tags as
+// defined by startTags and endTag) as follows:
+//
+// - if line >= 0, line numbers are printed before each line, starting
+// with the value of line
+// - if the text is Go source, comments get the "comment" span class
+// - each occurrence of the regular expression pattern gets the "highlight"
+// span class
+// - text segments covered by selection get the "selection" span class
+//
+// Comments, highlights, and selections may overlap arbitrarily; the respective
+// HTML span classes are specified in the startTags variable.
+//
+func FormatText(text []byte, line int, goSource bool, pattern string, selection Selection) []byte {
+ var buf bytes.Buffer
+ buf.WriteString("<pre>\n")
+
+ var comments, highlights Selection
+ if goSource {
+ comments = commentSelection(text)
+ }
+ if pattern != "" {
+ highlights = regexpSelection(text, pattern)
+ }
+ if 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)
+ line++
+ }
+ }
+ }
+ FormatSelections(&buf, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
+ } else {
+ template.HTMLEscape(&buf, text)
+ }
+
+ buf.WriteString("</pre>\n")
+ return buf.Bytes()
+}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 61c53e2c3..d6054ab9d 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -21,43 +21,15 @@ import (
pathutil "path"
"regexp"
"runtime"
+ "sort"
"strings"
- "sync"
"template"
"time"
- "unicode"
"utf8"
)
// ----------------------------------------------------------------------------
-// Support types
-
-// 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{}
- timestamp int64 // time of last set(), in seconds since epoch
-}
-
-
-func (v *RWValue) set(value interface{}) {
- v.mutex.Lock()
- v.value = value
- v.timestamp = time.Seconds()
- v.mutex.Unlock()
-}
-
-
-func (v *RWValue) get() (interface{}, int64) {
- v.mutex.RLock()
- defer v.mutex.RUnlock()
- return v.value, v.timestamp
-}
-
-
-// ----------------------------------------------------------------------------
// Globals
type delayTime struct {
@@ -72,6 +44,7 @@ func (dt *delayTime) backoff(max int) {
v = max
}
dt.value = v
+ // don't change dt.timestamp - calling backoff indicates an error condition
dt.mutex.Unlock()
}
@@ -80,15 +53,24 @@ var (
verbose = flag.Bool("v", false, "verbose mode")
// file system roots
- goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
- path = flag.String("path", "", "additional package directories (colon-separated)")
+ // 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)")
+ 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
// layout control
- tabwidth = flag.Int("tabwidth", 4, "tab width")
+ 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")
// file system mapping
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
+ fsMap Mapping // user-defined mapping
+ fsTree RWValue // *Directory tree of packages, updated with each sync
+ pathFilter RWValue // filter used when building fsMap directory trees
+ fsModified RWValue // timestamp of last call to invalidateIndex
// http handlers
fileServer http.Handler // default file server
@@ -114,410 +96,179 @@ func registerPublicHandlers(mux *http.ServeMux) {
}
-// ----------------------------------------------------------------------------
-// Predicates and small utility functions
-
-func isGoFile(f *os.FileInfo) bool {
- return f.IsRegular() &&
- !strings.HasPrefix(f.Name, ".") && // ignore .files
- pathutil.Ext(f.Name) == ".go"
-}
-
-
-func isPkgFile(f *os.FileInfo) bool {
- return isGoFile(f) &&
- !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+func initFSTree() {
+ fsTree.set(newDirectory(pathutil.Join(*goroot, *testDir), nil, -1))
+ invalidateIndex()
}
-func isPkgDir(f *os.FileInfo) bool {
- return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
-}
-
-
-func pkgName(filename string) string {
- file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly)
- if err != nil || file == nil {
- return ""
- }
- return file.Name.Name()
-}
-
+// ----------------------------------------------------------------------------
+// Directory filters
-func htmlEscape(s string) string {
- var buf bytes.Buffer
- template.HTMLEscape(&buf, []byte(s))
- return buf.String()
+// isParentOf returns true if p is a parent of (or the same as) q
+// where p and q are directory paths.
+func isParentOf(p, q string) bool {
+ n := len(p)
+ return strings.HasPrefix(q, p) && (len(q) <= n || q[n] == '/')
}
-func firstSentence(s string) string {
- i := -1 // index+1 of first period
- j := -1 // index+1 of first period that is followed by white space
- prev := 'A'
- for k, ch := range s {
- k1 := k + 1
- if ch == '.' {
- if i < 0 {
- i = k1 // first period
- }
- if k1 < len(s) && s[k1] <= ' ' {
- if j < 0 {
- j = k1 // first period followed by white space
- }
- if !unicode.IsUpper(prev) {
- j = k1
- break
- }
- }
- }
- prev = ch
- }
-
- if j < 0 {
- // use the next best period
- j = i
- if j < 0 {
- // no period at all, use the entire string
- j = len(s)
- }
+func setPathFilter(list []string) {
+ if len(list) == 0 {
+ pathFilter.set(nil)
+ return
}
- return s[0:j]
+ // len(list) > 0
+ pathFilter.set(func(path string) bool {
+ // list is sorted in increasing order and for each path all its children are removed
+ i := sort.Search(len(list), func(i int) bool { return list[i] > path })
+ // Now we have list[i-1] <= path < list[i].
+ // Path may be a child of list[i-1] or a parent of list[i].
+ return i > 0 && isParentOf(list[i-1], path) || i < len(list) && isParentOf(path, list[i])
+ })
}
-func absolutePath(path, defaultRoot string) string {
- abspath := fsMap.ToAbsolute(path)
- if abspath == "" {
- // no user-defined mapping found; use default mapping
- abspath = pathutil.Join(defaultRoot, path)
+func getPathFilter() func(string) bool {
+ f, _ := pathFilter.get()
+ if f != nil {
+ return f.(func(string) bool)
}
- return abspath
+ return nil
}
-func relativePath(path string) string {
- relpath := fsMap.ToRelative(path)
- if relpath == "" && strings.HasPrefix(path, *goroot+"/") {
- // no user-defined mapping found; use default mapping
- relpath = path[len(*goroot)+1:]
+// readDirList reads a file containing a newline-separated list
+// of directory paths and returns the list of paths.
+func readDirList(filename string) ([]string, os.Error) {
+ contents, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
}
- // Only if path is an invalid absolute path is relpath == ""
- // at this point. This should never happen since absolute paths
- // are only created via godoc for files that do exist. However,
- // it is ok to return ""; it will simply provide a link to the
- // top of the pkg or src directories.
- return relpath
-}
-
-
-// ----------------------------------------------------------------------------
-// Package directories
-
-type Directory struct {
- Depth int
- Path string // includes Name
- Name string
- Text string // package documentation, if any
- Dirs []*Directory // subdirectories
-}
-
-
-func newDirTree(path, name string, depth, maxDepth int) *Directory {
- if depth >= maxDepth {
- // return a dummy directory so that the parent directory
- // doesn't get discarded just because we reached the max
- // directory depth
- return &Directory{depth, path, name, "", nil}
+ // create a sorted list of valid directory names
+ filter := func(path string) bool {
+ d, err := os.Lstat(path)
+ return err == nil && isPkgDir(d)
}
-
- list, _ := ioutil.ReadDir(path) // ignore errors
-
- // determine number of subdirectories and package files
- ndirs := 0
- nfiles := 0
- text := ""
- for _, d := range list {
- switch {
- case isPkgDir(d):
- ndirs++
- case isPkgFile(d):
- nfiles++
- if text == "" {
- // no package documentation yet; take the first found
- file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil, nil,
- parser.ParseComments|parser.PackageClauseOnly)
- if err == nil &&
- // Also accept fakePkgName, so we get synopses for commmands.
- // Note: This may lead to incorrect results if there is a
- // (left-over) "documentation" package somewhere in a package
- // directory of different name, but this is very unlikely and
- // against current conventions.
- (file.Name.Name() == name || file.Name.Name() == fakePkgName) &&
- file.Doc != nil {
- // found documentation; extract a synopsys
- text = firstSentence(doc.CommentText(file.Doc))
- }
- }
- }
- }
-
- // create subdirectory tree
- var dirs []*Directory
- if ndirs > 0 {
- dirs = make([]*Directory, ndirs)
- i := 0
- for _, d := range list {
- if isPkgDir(d) {
- dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1, maxDepth)
- if dd != nil {
- dirs[i] = dd
- i++
- }
- }
+ list := canonicalizePaths(strings.Split(string(contents), "\n", -1), filter)
+ // for each parent path, remove all it's children q
+ // (requirement for binary search to work when filtering)
+ i := 0
+ for _, q := range list {
+ if i == 0 || !isParentOf(list[i-1], q) {
+ list[i] = q
+ i++
}
- dirs = dirs[0:i]
}
-
- // if there are no package files and no subdirectories
- // (with package files), ignore the directory
- if nfiles == 0 && len(dirs) == 0 {
- return nil
- }
-
- return &Directory{depth, path, name, text, dirs}
+ return list[0:i], nil
}
-// newDirectory creates a new package directory tree with at most maxDepth
-// levels, anchored at root which is relative to goroot. The result tree
-// only contains directories that contain package files or that contain
-// subdirectories containing package files (transitively).
+// updateMappedDirs computes the directory tree for
+// each user-defined file system mapping. If a filter
+// is provided, it is used to filter directories.
//
-func newDirectory(root string, maxDepth int) *Directory {
- d, err := os.Lstat(root)
- if err != nil || !isPkgDir(d) {
- return nil
- }
- return newDirTree(root, d.Name, 0, maxDepth)
-}
-
-
-func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
- if dir != nil {
- if !skipRoot {
- c <- dir
- }
- for _, d := range dir.Dirs {
- d.walk(c, false)
- }
+func updateMappedDirs(filter func(string) bool) {
+ if !fsMap.IsEmpty() {
+ fsMap.Iterate(func(path string, value *RWValue) bool {
+ value.set(newDirectory(path, filter, -1))
+ return true
+ })
+ invalidateIndex()
}
}
-func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
- c := make(chan *Directory)
- go func() {
- dir.walk(c, skipRoot)
- close(c)
- }()
- return c
-}
-
+func updateFilterFile() {
+ updateMappedDirs(nil) // no filter for accuracy
-func (dir *Directory) lookupLocal(name string) *Directory {
- for _, d := range dir.Dirs {
- if d.Name == name {
- return d
+ // collect directory tree leaf node paths
+ var buf bytes.Buffer
+ fsMap.Iterate(func(_ string, value *RWValue) bool {
+ v, _ := value.get()
+ if v != nil && v.(*Directory) != nil {
+ v.(*Directory).writeLeafs(&buf)
}
- }
- return nil
-}
+ return true
+ })
-
-// lookup looks for the *Directory for a given path, relative to dir.
-func (dir *Directory) lookup(path string) *Directory {
- d := strings.Split(dir.Path, "/", -1)
- p := strings.Split(path, "/", -1)
- i := 0
- for i < len(d) {
- if i >= len(p) || d[i] != p[i] {
- return nil
- }
- i++
- }
- for dir != nil && i < len(p) {
- dir = dir.lookupLocal(p[i])
- i++
+ // update filter file
+ if err := writeFileAtomically(*filter, buf.Bytes()); err != nil {
+ log.Printf("writeFileAtomically(%s): %s", *filter, err)
+ filterDelay.backoff(24 * 60) // back off exponentially, but try at least once a day
+ } else {
+ filterDelay.set(*filterMin) // revert to regular filter update schedule
}
- return dir
-}
-
-
-// DirEntry describes a directory entry. The Depth and Height values
-// are useful for presenting an entry in an indented fashion.
-//
-type DirEntry struct {
- Depth int // >= 0
- Height int // = DirList.MaxHeight - Depth, > 0
- Path string // includes Name, relative to DirList root
- Name string
- Synopsis string
}
-type DirList struct {
- MaxHeight int // directory tree height, > 0
- List []DirEntry
-}
-
-
-// listing creates a (linear) directory listing from a directory tree.
-// If skipRoot is set, the root directory itself is excluded from the list.
-//
-func (root *Directory) listing(skipRoot bool) *DirList {
- if root == nil {
- return nil
- }
-
- // determine number of entries n and maximum height
- n := 0
- minDepth := 1 << 30 // infinity
- maxDepth := 0
- for d := range root.iter(skipRoot) {
- n++
- if minDepth > d.Depth {
- minDepth = d.Depth
- }
- if maxDepth < d.Depth {
- maxDepth = d.Depth
+func initDirTrees() {
+ // setup initial path filter
+ if *filter != "" {
+ list, err := readDirList(*filter)
+ if err != nil {
+ log.Printf("%s", err)
+ } else if len(list) == 0 {
+ log.Printf("no directory paths in file %s", *filter)
}
+ setPathFilter(list)
}
- maxHeight := maxDepth - minDepth + 1
- if n == 0 {
- return nil
- }
+ go updateMappedDirs(getPathFilter()) // use filter for speed
- // create list
- list := make([]DirEntry, n)
- i := 0
- for d := range root.iter(skipRoot) {
- p := &list[i]
- p.Depth = d.Depth - minDepth
- p.Height = maxHeight - p.Depth
- // the path is relative to root.Path - remove the root.Path
- // prefix (the prefix should always be present but avoid
- // crashes and check)
- path := d.Path
- if strings.HasPrefix(d.Path, root.Path) {
- path = d.Path[len(root.Path):]
- }
- // remove trailing '/' if any - path must be relative
- if len(path) > 0 && path[0] == '/' {
- path = path[1:]
- }
- p.Path = path
- p.Name = d.Name
- p.Synopsis = d.Text
- i++
+ // start filter update goroutine, if enabled.
+ if *filter != "" && *filterMin > 0 {
+ filterDelay.set(*filterMin) // initial filter update delay
+ go func() {
+ for {
+ if *verbose {
+ log.Printf("start update of %s", *filter)
+ }
+ updateFilterFile()
+ delay, _ := filterDelay.get()
+ if *verbose {
+ log.Printf("next filter update in %dmin", delay.(int))
+ }
+ time.Sleep(int64(delay.(int)) * 60e9)
+ }
+ }()
}
-
- return &DirList{maxHeight, list}
}
// ----------------------------------------------------------------------------
-// HTML formatting support
-
-// Styler implements a printer.Styler.
-type Styler struct {
- linetags bool
- highlight string
- objmap map[*ast.Object]int
- count int
-}
-
-
-func newStyler(highlight string) *Styler {
- return &Styler{true, highlight, make(map[*ast.Object]int), 0}
-}
+// Path mapping
-
-func (s *Styler) id(obj *ast.Object) int {
- n, found := s.objmap[obj]
- if !found {
- n = s.count
- s.objmap[obj] = n
- s.count++
- }
- return n
-}
-
-
-func (s *Styler) mapping() []*ast.Object {
- if s.objmap == nil {
- return nil
- }
- m := make([]*ast.Object, s.count)
- for obj, i := range s.objmap {
- m[i] = obj
- }
- return m
-}
-
-
-// Use the defaultStyler when there is no specific styler.
-// The defaultStyler does not emit line tags since they may
-// interfere with tags emitted by templates.
-// TODO(gri): Should emit line tags at the beginning of a line;
-// never in the middle of code.
-var defaultStyler Styler
-
-
-func (s *Styler) LineTag(line int) (text []byte, tag printer.HTMLTag) {
- if s.linetags {
- tag = printer.HTMLTag{fmt.Sprintf(`<a id="L%d">`, line), "</a>"}
+func absolutePath(path, defaultRoot string) string {
+ abspath := fsMap.ToAbsolute(path)
+ if abspath == "" {
+ // no user-defined mapping found; use default mapping
+ abspath = pathutil.Join(defaultRoot, path)
}
- return
-}
-
-
-func (s *Styler) Comment(c *ast.Comment, line []byte) (text []byte, tag printer.HTMLTag) {
- text = line
- // minimal syntax-coloring of comments for now - people will want more
- // (don't do anything more until there's a button to turn it on/off)
- tag = printer.HTMLTag{`<span class="comment">`, "</span>"}
- return
-}
-
-
-func (s *Styler) BasicLit(x *ast.BasicLit) (text []byte, tag printer.HTMLTag) {
- text = x.Value
- return
+ return abspath
}
-func (s *Styler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
- text = []byte(id.Name())
- var str string
- if s.objmap != nil {
- str = fmt.Sprintf(` id="%d"`, s.id(id.Obj))
- }
- if s.highlight == id.Name() {
- str += ` class="highlight"`
- }
- if str != "" {
- tag = printer.HTMLTag{"<span" + str + ">", "</span>"}
+func relativePath(path string) string {
+ relpath := fsMap.ToRelative(path)
+ if relpath == "" {
+ // prefix must end in '/'
+ prefix := *goroot
+ if len(prefix) > 0 && prefix[len(prefix)-1] != '/' {
+ prefix += "/"
+ }
+ if strings.HasPrefix(path, prefix) {
+ // no user-defined mapping found; use default mapping
+ relpath = path[len(prefix):]
+ }
}
- return
-}
-
-
-func (s *Styler) Token(tok token.Token) (text []byte, tag printer.HTMLTag) {
- text = []byte(tok.String())
- return
+ // Only if path is an invalid absolute path is relpath == ""
+ // at this point. This should never happen since absolute paths
+ // are only created via godoc for files that do exist. However,
+ // it is ok to return ""; it will simply provide a link to the
+ // top of the pkg or src directories.
+ return relpath
}
@@ -597,7 +348,7 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) {
// Templates
// Write an AST-node to w; optionally html-escaped.
-func writeNode(w io.Writer, node interface{}, html bool, styler printer.Styler) {
+func writeNode(w io.Writer, fset *token.FileSet, node interface{}, html bool) {
mode := printer.TabIndent | printer.UseSpaces
if html {
mode |= printer.GenHTML
@@ -606,7 +357,7 @@ func writeNode(w io.Writer, node interface{}, html bool, styler printer.Styler)
// to ensure a good outcome in most browsers (there may still
// be tabs in comments and strings, but converting those into
// the right number of spaces is much harder)
- (&printer.Config{mode, *tabwidth, styler}).Fprint(&tconv{output: w}, node)
+ (&printer.Config{mode, *tabwidth, nil}).Fprint(&tconv{output: w}, fset, node)
}
@@ -621,14 +372,14 @@ func writeText(w io.Writer, text []byte, html bool) {
// Write anything to w; optionally html-escaped.
-func writeAny(w io.Writer, x interface{}, html bool) {
+func writeAny(w io.Writer, fset *token.FileSet, html bool, x interface{}) {
switch v := x.(type) {
case []byte:
writeText(w, v, html)
case string:
writeText(w, []byte(v), html)
case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
- writeNode(w, x, html, &defaultStyler)
+ writeNode(w, fset, x, html)
default:
if html {
var buf bytes.Buffer
@@ -641,24 +392,34 @@ func writeAny(w io.Writer, x interface{}, html bool) {
}
+func fileset(x []interface{}) *token.FileSet {
+ if len(x) > 1 {
+ if fset, ok := x[1].(*token.FileSet); ok {
+ return fset
+ }
+ }
+ return nil
+}
+
+
// Template formatter for "html" format.
-func htmlFmt(w io.Writer, x interface{}, format string) {
- writeAny(w, x, true)
+func htmlFmt(w io.Writer, format string, x ...interface{}) {
+ writeAny(w, fileset(x), true, x[0])
}
// Template formatter for "html-esc" format.
-func htmlEscFmt(w io.Writer, x interface{}, format string) {
+func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer
- writeAny(&buf, x, false)
+ writeAny(&buf, fileset(x), false, x[0])
template.HTMLEscape(w, buf.Bytes())
}
// Template formatter for "html-comment" format.
-func htmlCommentFmt(w io.Writer, x interface{}, format string) {
+func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer
- writeAny(&buf, x, false)
+ writeAny(&buf, fileset(x), false, x[0])
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
@@ -666,29 +427,49 @@ func htmlCommentFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "" (default) format.
-func textFmt(w io.Writer, x interface{}, format string) {
- writeAny(w, x, false)
+func textFmt(w io.Writer, format string, x ...interface{}) {
+ writeAny(w, fileset(x), false, x[0])
+}
+
+
+// Template formatter for "urlquery-esc" format.
+func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
+ var buf bytes.Buffer
+ writeAny(&buf, fileset(x), false, x[0])
+ template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes()))))
}
-// Template formatter for the various "url-xxx" formats.
-func urlFmt(w io.Writer, x interface{}, format string) {
+// Template formatter for the various "url-xxx" formats excluding url-esc.
+func urlFmt(w io.Writer, format string, x ...interface{}) {
var path string
var line int
+ var low, high int // selection
// determine path and position info, if any
type positioner interface {
- Pos() token.Position
+ Pos() token.Pos
+ End() token.Pos
}
- switch t := x.(type) {
+ switch t := x[0].(type) {
case string:
path = t
case positioner:
- pos := t.Pos()
- if pos.IsValid() {
+ fset := fileset(x)
+ if p := t.Pos(); p.IsValid() {
+ pos := fset.Position(p)
path = pos.Filename
line = pos.Line
+ low = pos.Offset
}
+ if p := t.End(); p.IsValid() {
+ high = fset.Position(p).Offset
+ }
+ default:
+ // we should never reach here, but be resilient
+ // and assume the position is invalid (empty path,
+ // and line 0)
+ log.Printf("INTERNAL ERROR: urlFmt(%s) without a string or positioner", format)
}
// map path
@@ -700,7 +481,7 @@ func urlFmt(w io.Writer, x interface{}, format string) {
default:
// we should never reach here, but be resilient
// and assume the url-pkg format instead
- log.Stderrf("INTERNAL ERROR: urlFmt(%s)", format)
+ log.Printf("INTERNAL ERROR: urlFmt(%s)", format)
fallthrough
case "url-pkg":
// because of the irregular mapping under goroot
@@ -712,10 +493,22 @@ func urlFmt(w io.Writer, x interface{}, format string) {
case "url-src":
template.HTMLEscape(w, []byte(relpath))
case "url-pos":
+ template.HTMLEscape(w, []byte(relpath))
+ // selection ranges are of form "s=low:high"
+ if low < high {
+ fmt.Fprintf(w, "?s=%d:%d", low, high)
+ // if we have a selection, position the page
+ // such that the selection is a bit below the top
+ line -= 10
+ if line < 1 {
+ line = 1
+ }
+ }
// line id's in html-printed source are of the
// form "L%d" where %d stands for the line number
- template.HTMLEscape(w, []byte(relpath))
- fmt.Fprintf(w, "#L%d", line)
+ if line > 0 {
+ fmt.Fprintf(w, "#L%d", line)
+ }
}
}
@@ -734,14 +527,14 @@ var infoKinds = [nKinds]string{
// Template formatter for "infoKind" format.
-func infoKindFmt(w io.Writer, x interface{}, format string) {
- fmt.Fprintf(w, infoKinds[x.(SpotKind)]) // infoKind entries are html-escaped
+func infoKindFmt(w io.Writer, format string, x ...interface{}) {
+ fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
}
// Template formatter for "infoLine" format.
-func infoLineFmt(w io.Writer, x interface{}, format string) {
- info := x.(SpotInfo)
+func infoLineFmt(w io.Writer, format string, x ...interface{}) {
+ info := x[0].(SpotInfo)
line := info.Lori()
if info.IsIndex() {
index, _ := searchIndex.get()
@@ -760,58 +553,52 @@ func infoLineFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "infoSnippet" format.
-func infoSnippetFmt(w io.Writer, x interface{}, format string) {
- info := x.(SpotInfo)
- text := `<span class="alert">no snippet text available</span>`
+func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
+ info := x[0].(SpotInfo)
+ text := []byte(`<span class="alert">no snippet text available</span>`)
if info.IsIndex() {
index, _ := searchIndex.get()
// no escaping of snippet text needed;
// snippet text is escaped when generated
text = index.(*Index).Snippet(info.Lori()).Text
}
- fmt.Fprint(w, text)
+ w.Write(text)
}
// Template formatter for "padding" format.
-func paddingFmt(w io.Writer, x interface{}, format string) {
- for i := x.(int); i > 0; i-- {
+func paddingFmt(w io.Writer, format string, x ...interface{}) {
+ for i := x[0].(int); i > 0; i-- {
fmt.Fprint(w, `<td width="25"></td>`)
}
}
// Template formatter for "time" format.
-func timeFmt(w io.Writer, x interface{}, format string) {
- template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x.(int64)/1e9).String()))
+func timeFmt(w io.Writer, format string, x ...interface{}) {
+ template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String()))
}
// Template formatter for "dir/" format.
-func dirslashFmt(w io.Writer, x interface{}, format string) {
- if x.(*os.FileInfo).IsDirectory() {
+func dirslashFmt(w io.Writer, format string, x ...interface{}) {
+ if x[0].(*os.FileInfo).IsDirectory() {
w.Write([]byte{'/'})
}
}
// Template formatter for "localname" format.
-func localnameFmt(w io.Writer, x interface{}, format string) {
- _, localname := pathutil.Split(x.(string))
+func localnameFmt(w io.Writer, format string, x ...interface{}) {
+ _, localname := pathutil.Split(x[0].(string))
template.HTMLEscape(w, []byte(localname))
}
-// Template formatter for "popupInfo" format.
-func popupInfoFmt(w io.Writer, x interface{}, format string) {
- obj := x.(*ast.Object)
- // for now, show object kind and name; eventually
- // do something more interesting (show declaration,
- // for instance)
- if obj.Kind != ast.Err {
- fmt.Fprintf(w, "%s ", obj.Kind)
- }
- template.HTMLEscape(w, []byte(obj.Name))
+// Template formatter for "numlines" format.
+func numlinesFmt(w io.Writer, format string, x ...interface{}) {
+ list := x[0].([]int)
+ fmt.Fprintf(w, "%d", len(list))
}
@@ -820,6 +607,7 @@ var fmap = template.FormatterMap{
"html": htmlFmt,
"html-esc": htmlEscFmt,
"html-comment": htmlCommentFmt,
+ "urlquery-esc": urlQueryEscFmt,
"url-pkg": urlFmt,
"url-src": urlFmt,
"url-pos": urlFmt,
@@ -830,7 +618,7 @@ var fmap = template.FormatterMap{
"time": timeFmt,
"dir/": dirslashFmt,
"localname": localnameFmt,
- "popupInfo": popupInfoFmt,
+ "numlines": numlinesFmt,
}
@@ -857,8 +645,7 @@ var (
packageHTML,
packageText,
searchHTML,
- searchText,
- sourceHTML *template.Template
+ searchText *template.Template
)
func readTemplates() {
@@ -872,46 +659,40 @@ func readTemplates() {
packageText = readTemplate("package.txt")
searchHTML = readTemplate("search.html")
searchText = readTemplate("search.txt")
- sourceHTML = readTemplate("source.html")
}
// ----------------------------------------------------------------------------
// Generic HTML wrapper
-func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
- type Data struct {
- Title string
- Subtitle string
- PkgRoots []string
- Timestamp int64
- Query string
- Version string
- Menu []byte
- Content []byte
- }
-
- _, ts := fsTree.get()
- d := Data{
- Title: title,
- Subtitle: subtitle,
- PkgRoots: fsMap.PrefixList(),
- Timestamp: ts * 1e9, // timestamp in ns
- Query: query,
- Version: runtime.Version(),
- Menu: nil,
- Content: content,
- }
-
- if err := godocHTML.Execute(&d, c); err != nil {
- log.Stderrf("godocHTML.Execute: %s", err)
+func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
+ d := struct {
+ Title string
+ Subtitle string
+ PkgRoots []string
+ Query string
+ Version string
+ Menu []byte
+ Content []byte
+ }{
+ title,
+ subtitle,
+ fsMap.PrefixList(),
+ query,
+ runtime.Version(),
+ nil,
+ content,
+ }
+
+ if err := godocHTML.Execute(&d, w); err != nil {
+ log.Printf("godocHTML.Execute: %s", err)
}
}
-func serveText(c *http.Conn, text []byte) {
- c.SetHeader("Content-Type", "text/plain; charset=utf-8")
- c.Write(text)
+func serveText(w http.ResponseWriter, text []byte) {
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.Write(text)
}
@@ -926,27 +707,27 @@ var (
func extractString(src []byte, rx *regexp.Regexp) (s string) {
- m := rx.Execute(src)
- if len(m) >= 4 {
- s = strings.TrimSpace(string(src[m[2]:m[3]]))
+ m := rx.FindSubmatch(src)
+ if m != nil {
+ s = strings.TrimSpace(string(m[1]))
}
return
}
-func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
// get HTML body contents
src, err := ioutil.ReadFile(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadFile: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadFile: %s", err)
+ serveError(w, r, relpath, err)
return
}
// if it begins with "<!DOCTYPE " assume it is standalone
// html that doesn't need the template wrapping.
if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
- c.Write(src)
+ w.Write(src)
return
}
@@ -965,45 +746,22 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
}
subtitle := extractString(src, subtitleRx)
- servePage(c, title, subtitle, "", src)
+ servePage(w, title, subtitle, "", src)
}
func applyTemplate(t *template.Template, name string, data interface{}) []byte {
var buf bytes.Buffer
if err := t.Execute(data, &buf); err != nil {
- log.Stderrf("%s.Execute: %s", name, err)
+ log.Printf("%s.Execute: %s", name, err)
}
return buf.Bytes()
}
-func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
- file, err := parser.ParseFile(abspath, nil, nil, parser.ParseComments)
- if err != nil {
- log.Stderrf("parser.ParseFile: %s", err)
- serveError(c, r, relpath, err)
- return
- }
-
- var buf bytes.Buffer
- styler := newStyler(r.FormValue("h"))
- writeNode(&buf, file, true, styler)
-
- type SourceInfo struct {
- Source []byte
- Data []*ast.Object
- }
- info := &SourceInfo{buf.Bytes(), styler.mapping()}
-
- contents := applyTemplate(sourceHTML, "sourceHTML", info)
- servePage(c, "Source file "+relpath, "", "", contents)
-}
-
-
-func redirect(c *http.Conn, r *http.Request) (redirected bool) {
+func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
if canonical := pathutil.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
- http.Redirect(c, canonical, http.StatusMovedPermanently)
+ http.Redirect(w, r, canonical, http.StatusMovedPermanently)
redirected = true
}
return
@@ -1057,32 +815,28 @@ func isTextFile(path string) bool {
}
-func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
src, err := ioutil.ReadFile(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadFile: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadFile: %s", err)
+ serveError(w, r, relpath, err)
return
}
- var buf bytes.Buffer
- fmt.Fprintln(&buf, "<pre>")
- template.HTMLEscape(&buf, src)
- fmt.Fprintln(&buf, "</pre>")
-
- servePage(c, "Text file "+relpath, "", "", buf.Bytes())
+ contents := FormatText(src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+ servePage(w, title+" "+relpath, "", "", contents)
}
-func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
- if redirect(c, r) {
+func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ if redirect(w, r) {
return
}
list, err := ioutil.ReadDir(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadDir: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadDir: %s", err)
+ serveError(w, r, relpath, err)
return
}
@@ -1093,23 +847,23 @@ func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
}
contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
- servePage(c, "Directory "+relpath, "", "", contents)
+ servePage(w, "Directory "+relpath, "", "", contents)
}
-func serveFile(c *http.Conn, r *http.Request) {
+func serveFile(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[1:] // serveFile URL paths start with '/'
abspath := absolutePath(relpath, *goroot)
// pick off special cases and hand the rest to the standard file server
switch r.URL.Path {
case "/":
- serveHTMLDoc(c, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
+ serveHTMLDoc(w, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
return
case "/doc/root.html":
// hide landing page from its real name
- http.Redirect(c, "/", http.StatusMovedPermanently)
+ http.Redirect(w, r, "/", http.StatusMovedPermanently)
return
}
@@ -1118,42 +872,42 @@ func serveFile(c *http.Conn, r *http.Request) {
if strings.HasSuffix(abspath, "/index.html") {
// We'll show index.html for the directory.
// Use the dir/ version as canonical instead of dir/index.html.
- http.Redirect(c, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
+ http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
return
}
- serveHTMLDoc(c, r, abspath, relpath)
+ serveHTMLDoc(w, r, abspath, relpath)
return
case ".go":
- serveGoSource(c, r, abspath, relpath)
+ serveTextFile(w, r, abspath, relpath, "Source file")
return
}
dir, err := os.Lstat(abspath)
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
if dir != nil && dir.IsDirectory() {
- if redirect(c, r) {
+ if redirect(w, r) {
return
}
if index := abspath + "/index.html"; isTextFile(index) {
- serveHTMLDoc(c, r, index, relativePath(index))
+ serveHTMLDoc(w, r, index, relativePath(index))
return
}
- serveDirectory(c, r, abspath, relpath)
+ serveDirectory(w, r, abspath, relpath)
return
}
if isTextFile(abspath) {
- serveTextFile(c, r, abspath, relpath)
+ serveTextFile(w, r, abspath, relpath, "Text file")
return
}
- fileServer.ServeHTTP(c, r)
+ fileServer.ServeHTTP(w, r)
}
@@ -1169,17 +923,19 @@ type PageInfoMode uint
const (
exportsOnly PageInfoMode = 1 << iota // only keep exported stuff
genDoc // generate documentation
- tryMode // don't log errors
)
type PageInfo struct {
Dirname string // directory containing the package
PList []string // list of package names found
+ FSet *token.FileSet // corresponding file set
PAst *ast.File // nil if no single AST with package exports
PDoc *doc.PackageDoc // nil if no single package documentation
Dirs *DirList // nil if no directory information
+ DirTime int64 // directory time stamp in seconds since epoch
IsPkg bool // false if this is not documenting a real package
+ Err os.Error // directory read error or nil
}
@@ -1193,10 +949,10 @@ type httpHandler struct {
// getPageInfo returns the PageInfo for a package directory abspath. If the
// parameter genAST is set, an AST containing only the package exports is
// computed (PageInfo.PAst), otherwise package documentation (PageInfo.Doc)
-// is extracted from the AST. If the parameter try is set, no errors are
-// logged if getPageInfo fails. If there is no corresponding package in the
-// directory, PageInfo.PDoc and PageInfo.PExp are nil. If there are no sub-
-// directories, PageInfo.Dirs is nil.
+// is extracted from the AST. If there is no corresponding package in the
+// directory, PageInfo.PAst and PageInfo.PDoc are nil. If there are no sub-
+// directories, PageInfo.Dirs is nil. If a directory read error occurred,
+// PageInfo.Err is set to the respective error but the error is not logged.
//
func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInfoMode) PageInfo {
// filter function to select the desired .go files
@@ -1207,10 +963,12 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
}
// get package ASTs
- pkgs, err := parser.ParseDir(abspath, filter, parser.ParseComments)
- if err != nil && mode&tryMode != 0 {
- // TODO: errors should be shown instead of an empty directory
- log.Stderrf("parser.parseDir: %s", err)
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, abspath, filter, parser.ParseComments)
+ if err != nil && pkgs == nil {
+ // only report directory read errors, ignore parse errors
+ // (may be able to extract partial package information)
+ return PageInfo{Dirname: abspath, Err: err}
}
// select package
@@ -1258,7 +1016,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// (excluding the selected package, if any).
plist = make([]string, len(pkgs))
i := 0
- for name, _ := range pkgs {
+ for name := range pkgs {
if pkg == nil || name != pkg.Name {
plist[i] = name
i++
@@ -1283,26 +1041,52 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// get directory information
var dir *Directory
- if tree, _ := fsTree.get(); tree != nil && tree.(*Directory) != nil {
+ var timestamp int64
+ if tree, ts := fsTree.get(); tree != nil && tree.(*Directory) != nil {
// directory tree is present; lookup respective directory
// (may still fail if the file system was updated and the
// new directory tree has not yet been computed)
- // TODO(gri) Need to build directory tree for fsMap entries
dir = tree.(*Directory).lookup(abspath)
+ timestamp = ts
+ }
+ if dir == nil {
+ // the path may refer to a user-specified file system mapped
+ // via fsMap; lookup that mapping and corresponding RWValue
+ // if any
+ var v *RWValue
+ fsMap.Iterate(func(path string, value *RWValue) bool {
+ if isParentOf(path, abspath) {
+ // mapping found
+ v = value
+ return false
+ }
+ return true
+ })
+ if v != nil {
+ // found a RWValue associated with a user-specified file
+ // system; a non-nil RWValue stores a (possibly out-of-date)
+ // directory tree for that file system
+ if tree, ts := v.get(); tree != nil && tree.(*Directory) != nil {
+ dir = tree.(*Directory).lookup(abspath)
+ timestamp = ts
+ }
+ }
}
if dir == nil {
- // no directory tree present (either early after startup
- // or command-line mode, or we don't build a tree for the
- // directory; e.g. google3); compute one level for this page
- dir = newDirectory(abspath, 1)
+ // no directory tree present (too early after startup or
+ // command-line mode); compute one level for this page
+ // note: cannot use path filter here because in general
+ // it doesn't contain the fsTree path
+ dir = newDirectory(abspath, nil, 1)
+ timestamp = time.Seconds()
}
- return PageInfo{abspath, plist, past, pdoc, dir.listing(true), h.isPkg}
+ return PageInfo{abspath, plist, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
}
-func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
- if redirect(c, r) {
+func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if redirect(w, r) {
return
}
@@ -1313,17 +1097,22 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
mode |= genDoc
}
info := h.getPageInfo(abspath, relpath, r.FormValue("p"), mode)
+ if info.Err != nil {
+ log.Print(info.Err)
+ serveError(w, r, relpath, info.Err)
+ return
+ }
if r.FormValue("f") == "text" {
contents := applyTemplate(packageText, "packageText", info)
- serveText(c, contents)
+ serveText(w, contents)
return
}
- var title string
+ var title, subtitle string
switch {
case info.PAst != nil:
- title = "Package " + info.PAst.Name.Name()
+ title = "Package " + info.PAst.Name.Name
case info.PDoc != nil:
switch {
case h.isPkg:
@@ -1337,10 +1126,13 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
}
default:
title = "Directory " + relativePath(info.Dirname)
+ if *showTimestamps {
+ subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
+ }
}
contents := applyTemplate(packageHTML, "packageHTML", info)
- servePage(c, title, "", "", contents)
+ servePage(w, title, subtitle, "", contents)
}
@@ -1350,71 +1142,160 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
var searchIndex RWValue
type SearchResult struct {
- Query string
- Hit *LookupResult
- Alt *AltWords
- Illegal bool
- Accurate bool
+ Query string
+ Alert string // error or warning message
+
+ // identifier matches
+ Hit *LookupResult // identifier matches of Query
+ Alt *AltWords // alternative identifiers to look for
+
+ // textual matches
+ Found int // number of textual occurrences found
+ Textual []FileLines // textual matches of Query
+ Complete bool // true if all textual occurrences of Query are reported
}
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
+ }
+
if index, timestamp := searchIndex.get(); index != nil {
- result.Hit, result.Alt, result.Illegal = index.(*Index).Lookup(query)
- _, ts := fsTree.get()
- result.Accurate = timestamp >= ts
+ // 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
+ 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"
+ }
}
return
}
-func search(c *http.Conn, r *http.Request) {
+func search(w http.ResponseWriter, r *http.Request) {
query := strings.TrimSpace(r.FormValue("q"))
result := lookup(query)
if r.FormValue("f") == "text" {
contents := applyTemplate(searchText, "searchText", result)
- serveText(c, contents)
+ serveText(w, contents)
return
}
var title string
- if result.Hit != nil {
+ if result.Hit != nil || len(result.Textual) > 0 {
title = fmt.Sprintf(`Results for query %q`, query)
} else {
title = fmt.Sprintf(`No results found for query %q`, query)
}
contents := applyTemplate(searchHTML, "searchHTML", result)
- servePage(c, title, "", query, contents)
+ servePage(w, title, "", query, contents)
}
// ----------------------------------------------------------------------------
// Indexer
+// invalidateIndex should be called whenever any of the file systems
+// under godoc's observation change so that the indexer is kicked on.
+//
+func invalidateIndex() {
+ fsModified.set(nil)
+}
+
+
+// indexUpToDate() returns true if the search index is not older
+// than any of the file systems under godoc's observation.
+//
+func indexUpToDate() bool {
+ _, fsTime := fsModified.get()
+ _, siTime := searchIndex.get()
+ return fsTime <= siTime
+}
+
+
+// feedDirnames feeds the directory names of all directories
+// under the file system given by root to channel c.
+//
+func feedDirnames(root *RWValue, c chan<- string) {
+ if dir, _ := root.get(); dir != nil {
+ for d := range dir.(*Directory).iter(false) {
+ c <- d.Path
+ }
+ }
+}
+
+
+// fsDirnames() returns a channel sending all directory names
+// of all the file systems under godoc's observation.
+//
+func fsDirnames() <-chan string {
+ c := make(chan string, 256) // asynchronous for fewer context switches
+ go func() {
+ feedDirnames(&fsTree, c)
+ fsMap.Iterate(func(_ string, root *RWValue) bool {
+ feedDirnames(root, c)
+ return true
+ })
+ close(c)
+ }()
+ return c
+}
+
+
func indexer() {
for {
- _, ts := fsTree.get()
- if _, timestamp := searchIndex.get(); timestamp < ts {
+ if !indexUpToDate() {
// index possibly out of date - make a new one
- // (could use a channel to send an explicit signal
- // from the sync goroutine, but this solution is
- // more decoupled, trivial, and works well enough)
+ if *verbose {
+ log.Printf("updating index...")
+ }
start := time.Nanoseconds()
- index := NewIndex(*goroot)
+ index := NewIndex(fsDirnames(), *fulltextIndex)
stop := time.Nanoseconds()
searchIndex.set(index)
if *verbose {
secs := float64((stop-start)/1e6) / 1e3
- nwords, nspots := index.Size()
- log.Stderrf("index updated (%gs, %d unique words, %d spots)", secs, nwords, nspots)
+ stats := index.Stats()
+ log.Printf("index updated (%gs, %d bytes of source, %d files, %d lines, %d unique words, %d spots)",
+ secs, stats.Bytes, stats.Files, stats.Lines, stats.Words, stats.Spots)
}
- log.Stderrf("bytes=%d footprint=%d\n", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ log.Printf("before GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
runtime.GC()
- log.Stderrf("bytes=%d footprint=%d\n", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ log.Printf("after GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ }
+ var delay int64 = 60 * 1e9 // by default, try every 60s
+ if *testDir != "" {
+ // in test mode, try once a second for fast startup
+ delay = 1 * 1e9
}
- time.Sleep(1 * 60e9) // try once a minute
+ time.Sleep(delay)
}
}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 8745b8b0a..ba6fe9acd 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -3,11 +3,11 @@
// license that can be found in the LICENSE file.
// This file contains the infrastructure to create an
-// (identifier) index for a set of Go files.
+// identifier and full-text index for a set of Go files.
//
-// Basic indexing algorithm:
+// Algorithm for identifier index:
// - traverse all .go files of the file tree specified by root
-// - for each word (identifier) encountered, collect all occurences (spots)
+// - for each word (identifier) encountered, collect all occurrences (spots)
// into a list; this produces a list of spots for each word
// - reduce the lists: from a list of spots to a list of FileRuns,
// and from a list of FileRuns into a list of PakRuns
@@ -21,17 +21,34 @@
// (the line number for spots with snippets is stored in the snippet)
// - at the end, create lists of alternative spellings for a given
// word
+//
+// Algorithm for full text index:
+// - concatenate all source code in a byte buffer (in memory)
+// - add the files to a file set in lockstep as they are added to the byte
+// buffer such that a byte buffer offset corresponds to the Pos value for
+// that file location
+// - create a suffix array from the concatenated sources
+//
+// String lookup in full text index:
+// - use the suffix array to lookup a string's offsets - the offsets
+// correspond to the Pos values relative to the file set
+// - translate the Pos values back into file and line information and
+// sort the result
package main
import (
+ "bytes"
"container/vector"
"go/ast"
"go/parser"
"go/token"
"go/scanner"
+ "index/suffixarray"
+ "io/ioutil"
"os"
pathutil "path"
+ "regexp"
"sort"
"strings"
)
@@ -231,7 +248,7 @@ type File struct {
}
-// A Spot describes a single occurence of a word.
+// A Spot describes a single occurrence of a word.
type Spot struct {
File *File
Info SpotInfo
@@ -419,7 +436,17 @@ const excludeTestFiles = false
type IndexResult struct {
Decls RunList // package-level declarations (with snippets)
- Others RunList // all other occurences
+ Others RunList // all other occurrences
+}
+
+
+// Statistics provides statistics information for an index.
+type Statistics struct {
+ Bytes int // total size of indexed source files
+ Files int // number of indexed source files
+ Lines int // number of lines (all files)
+ Words int // number of different identifiers
+ Spots int // number of identifier occurrences
}
@@ -428,11 +455,14 @@ type IndexResult struct {
// interface for walking file trees, and the ast.Visitor interface for
// walking Go ASTs.
type Indexer struct {
+ fset *token.FileSet // file set for all indexed files
+ sources bytes.Buffer // concatenated sources
words map[string]*IndexResult // RunLists of Spots
snippets vector.Vector // vector of *Snippets, indexed by snippet indices
- file *File // current file
- decl ast.Decl // current decl
- nspots int // number of spots encountered
+ current *token.File // last file added to file set
+ file *File // AST for current file
+ decl ast.Decl // AST for current decl
+ stats Statistics
}
@@ -452,24 +482,24 @@ func (x *Indexer) visitComment(c *ast.CommentGroup) {
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
if id != nil {
- lists, found := x.words[id.Name()]
+ lists, found := x.words[id.Name]
if !found {
lists = new(IndexResult)
- x.words[id.Name()] = lists
+ x.words[id.Name] = lists
}
if kind == Use || x.decl == nil {
// not a declaration or no snippet required
- info := makeSpotInfo(kind, id.Pos().Line, false)
+ info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
lists.Others.Push(Spot{x.file, info})
} else {
// a declaration with snippet
- index := x.addSnippet(NewSnippet(x.decl, id))
+ index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
info := makeSpotInfo(kind, index, true)
lists.Decls.Push(Spot{x.file, info})
}
- x.nspots++
+ x.stats.Spots++
}
}
@@ -506,7 +536,7 @@ func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
}
-func (x *Indexer) Visit(node interface{}) ast.Visitor {
+func (x *Indexer) Visit(node ast.Node) ast.Visitor {
// TODO(gri): methods in interface types are categorized as VarDecl
switch n := node.(type) {
case nil:
@@ -578,16 +608,69 @@ func (x *Indexer) Visit(node interface{}) ast.Visitor {
}
-func (x *Indexer) VisitDir(path string, f *os.FileInfo) bool {
- return true
+func pkgName(filename string) string {
+ // use a new file set each time in order to not pollute the indexer's
+ // file set (which must stay in sync with the concatenated source code)
+ file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
+ if err != nil || file == nil {
+ return ""
+ }
+ return file.Name.Name
+}
+
+
+func (x *Indexer) addFile(filename string) *ast.File {
+ // open file
+ f, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ return nil
+ }
+ defer f.Close()
+
+ // The file set's base offset and x.sources size must be in lock-step;
+ // this permits the direct mapping of suffix array lookup results to
+ // to corresponding Pos values.
+ //
+ // When a file is added to the file set, it's offset base increases by
+ // the size of the file + 1; and the initial base offset is 1. Add an
+ // extra byte to the sources here.
+ x.sources.WriteByte(0)
+
+ // If the sources length doesn't match the file set base at this point
+ // the file set implementation changed or we have another error.
+ base := x.fset.Base()
+ if x.sources.Len() != base {
+ 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
+ }
+
+ // 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
+ }
+
+ return file
}
-func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
+func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
if !isGoFile(f) {
return
}
+ path := pathutil.Join(dirname, f.Name)
if excludeTestFiles && (!isPkgFile(f) || strings.HasPrefix(path, "test/")) {
return
}
@@ -596,15 +679,23 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
return
}
- file, err := parser.ParseFile(path, nil, nil, parser.ParseComments)
- if err != nil {
- return // ignore files with (parse) errors
+ file := x.addFile(path)
+ if file == nil {
+ return
}
+ // 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()}
+ pak := Pak{dir, file.Name.Name}
x.file = &File{path, pak}
ast.Walk(x, file)
+
+ // update statistics
+ // (count real file size as opposed to using the padded x.sources.Len())
+ x.stats.Bytes += x.current.Size()
+ x.stats.Files++
+ x.stats.Lines += x.current.LineCount()
}
@@ -613,30 +704,54 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
type LookupResult struct {
Decls HitList // package-level declarations (with snippets)
- Others HitList // all other occurences
+ Others HitList // all other occurrences
}
type Index struct {
+ fset *token.FileSet // file set used during indexing; nil if no textindex
+ suffixes *suffixarray.Index // suffixes for concatenated sources; nil if no textindex
words map[string]*LookupResult // maps words to hit lists
alts map[string]*AltWords // maps canonical(words) to lists of alternative spellings
snippets []*Snippet // all snippets, indexed by snippet index
- nspots int // number of spots indexed (a measure of the index size)
+ stats Statistics
}
func canonical(w string) string { return strings.ToLower(w) }
-// NewIndex creates a new index for the file tree rooted at root.
-func NewIndex(root string) *Index {
+// NewIndex creates a new index for the .go files
+// in the directories given by dirnames.
+//
+func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
var x Indexer
// initialize Indexer
+ x.fset = token.NewFileSet()
x.words = make(map[string]*IndexResult)
- // collect all Spots
- pathutil.Walk(root, &x, nil)
+ // index all files in the directories given by dirnames
+ for dirname := range dirnames {
+ list, err := ioutil.ReadDir(dirname)
+ if err != nil {
+ continue // ignore this directory
+ }
+ for _, f := range list {
+ if !f.IsDirectory() {
+ x.visitFile(dirname, f)
+ }
+ }
+ }
+
+ if !fulltextIndex {
+ // the file set, the current file, and the sources are
+ // not needed after indexing if no text index is built -
+ // help GC and clear them
+ x.fset = nil
+ x.sources.Reset()
+ x.current = nil // contains reference to fset!
+ }
// for each word, reduce the RunLists into a LookupResult;
// also collect the word with its canonical spelling in a
@@ -652,6 +767,7 @@ func NewIndex(root string) *Index {
}
wlist.Push(&wordPair{canonical(w), w})
}
+ x.stats.Words = len(words)
// reduce the word list {canonical(w), w} into
// a list of AltWords runs {canonical(w), {w}}
@@ -670,14 +786,19 @@ func NewIndex(root string) *Index {
snippets[i] = x.snippets.At(i).(*Snippet)
}
- return &Index{words, alts, snippets, x.nspots}
+ // create text index
+ var suffixes *suffixarray.Index
+ if fulltextIndex {
+ suffixes = suffixarray.New(x.sources.Bytes())
+ }
+
+ return &Index{x.fset, suffixes, words, alts, snippets, x.stats}
}
-// Size returns the number of different words and
-// spots indexed as a measure for the index size.
-func (x *Index) Size() (nwords int, nspots int) {
- return len(x.words), x.nspots
+// Stats() returns index statistics.
+func (x *Index) Stats() Statistics {
+ return x.stats
}
@@ -696,7 +817,7 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
func isIdentifier(s string) bool {
var S scanner.Scanner
- S.Init("", []byte(s), nil, 0)
+ S.Init(token.NewFileSet(), "", []byte(s), nil, 0)
if _, tok, _ := S.Scan(); tok == token.IDENT {
_, tok, _ := S.Scan()
return tok == token.EOF
@@ -707,14 +828,14 @@ func isIdentifier(s string) bool {
// For a given query, which is either a single identifier or a qualified
// identifier, Lookup returns a LookupResult, and a list of alternative
-// spellings, if any. If the query syntax is wrong, illegal is set.
-func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, illegal bool) {
+// spellings, if any. If the query syntax is wrong, an error is reported.
+func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, err os.Error) {
ss := strings.Split(query, ".", -1)
// check query syntax
for _, s := range ss {
if !isIdentifier(s) {
- illegal = true
+ err = os.NewError("all query parts must be identifiers")
return
}
}
@@ -734,7 +855,7 @@ func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, illega
}
default:
- illegal = true
+ err = os.NewError("query is not a (qualified) identifier")
}
return
@@ -748,3 +869,103 @@ func (x *Index) Snippet(i int) *Snippet {
}
return nil
}
+
+
+type positionList []struct {
+ filename string
+ line int
+}
+
+func (list positionList) Len() int { return len(list) }
+func (list positionList) Less(i, j int) bool { return list[i].filename < list[j].filename }
+func (list positionList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+
+// unique returns the list sorted and with duplicate entries removed
+func unique(list []int) []int {
+ sort.SortInts(list)
+ var last int
+ i := 0
+ for _, x := range list {
+ if i == 0 || x != last {
+ last = x
+ list[i] = x
+ i++
+ }
+ }
+ return list[0:i]
+}
+
+
+// A FileLines value specifies a file and line numbers within that file.
+type FileLines struct {
+ Filename string
+ Lines []int
+}
+
+
+// LookupRegexp returns the number of matches and the matches where a regular
+// expression r is found in the full text index. At most n matches are
+// returned (thus found <= n).
+//
+func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileLines) {
+ if x.suffixes == nil || n <= 0 {
+ return
+ }
+ // n > 0
+
+ var list positionList
+ // FindAllIndex may returns matches that span across file boundaries.
+ // Such matches are unlikely, buf after eliminating them we may end up
+ // with fewer than n matches. If we don't have enough at the end, redo
+ // the search with an increased value n1, but only if FindAllIndex
+ // returned all the requested matches in the first place (if it
+ // returned fewer than that there cannot be more).
+ for n1 := n; found < n; n1 += n - found {
+ found = 0
+ matches := x.suffixes.FindAllIndex(r, n1)
+ // compute files, exclude matches that span file boundaries,
+ // and map offsets to file-local offsets
+ list = make(positionList, len(matches))
+ for _, m := range matches {
+ // by construction, an offset corresponds to the Pos value
+ // for the file set - use it to get the file and line
+ p := token.Pos(m[0])
+ if file := x.fset.File(p); file != nil {
+ if base := file.Base(); base <= m[1] && m[1] <= base+file.Size() {
+ // match [m[0], m[1]) is within the file boundaries
+ list[found].filename = file.Name()
+ list[found].line = file.Line(p)
+ found++
+ }
+ }
+ }
+ if found == n || len(matches) < n1 {
+ // found all matches or there's no chance to find more
+ break
+ }
+ }
+ list = list[0:found]
+ sort.Sort(list) // sort by filename
+
+ // collect matches belonging to the same file
+ var last string
+ var lines []int
+ addLines := func() {
+ if len(lines) > 0 {
+ // remove duplicate lines
+ result = append(result, FileLines{last, unique(lines)})
+ lines = nil
+ }
+ }
+ for _, m := range list {
+ if m.filename != last {
+ addLines()
+ last = m.filename
+ }
+ lines = append(lines, m.line)
+ }
+ addLines()
+
+ return
+}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 7a9279a2f..fe3d22fb9 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -49,7 +49,7 @@ var (
// periodic sync
syncCmd = flag.String("sync", "", "sync command; disabled if empty")
syncMin = flag.Int("sync_minutes", 0, "sync interval in minutes; disabled if <= 0")
- syncDelay delayTime // actual sync delay in minutes; usually syncDelay == syncMin, but delay may back off exponentially
+ syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
// network
httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
@@ -64,29 +64,30 @@ var (
)
-func serveError(c *http.Conn, r *http.Request, relpath string, err os.Error) {
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
- servePage(c, "File "+relpath, "", "", contents)
+ w.WriteHeader(http.StatusNotFound)
+ servePage(w, "File "+relpath, "", "", contents)
}
-func exec(c *http.Conn, args []string) (status int) {
+func exec(rw http.ResponseWriter, args []string) (status int) {
r, w, err := os.Pipe()
if err != nil {
- log.Stderrf("os.Pipe(): %v\n", err)
+ log.Printf("os.Pipe(): %v", err)
return 2
}
bin := args[0]
fds := []*os.File{nil, w, w}
if *verbose {
- log.Stderrf("executing %v", args)
+ log.Printf("executing %v", args)
}
pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds)
defer r.Close()
w.Close()
if err != nil {
- log.Stderrf("os.ForkExec(%q): %v\n", bin, err)
+ log.Printf("os.ForkExec(%q): %v", bin, err)
return 2
}
@@ -95,41 +96,38 @@ func exec(c *http.Conn, args []string) (status int) {
wait, err := os.Wait(pid, 0)
if err != nil {
os.Stderr.Write(buf.Bytes())
- log.Stderrf("os.Wait(%d, 0): %v\n", pid, err)
+ log.Printf("os.Wait(%d, 0): %v", pid, err)
return 2
}
status = wait.ExitStatus()
if !wait.Exited() || status > 1 {
os.Stderr.Write(buf.Bytes())
- log.Stderrf("executing %v failed (exit status = %d)", args, status)
+ log.Printf("executing %v failed (exit status = %d)", args, status)
return
}
if *verbose {
os.Stderr.Write(buf.Bytes())
}
- if c != nil {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- c.Write(buf.Bytes())
+ if rw != nil {
+ rw.SetHeader("content-type", "text/plain; charset=utf-8")
+ rw.Write(buf.Bytes())
}
return
}
-// Maximum directory depth, adjust as needed.
-const maxDirDepth = 24
-
-func dosync(c *http.Conn, r *http.Request) {
+func dosync(w http.ResponseWriter, r *http.Request) {
args := []string{"/bin/sh", "-c", *syncCmd}
- switch exec(c, args) {
+ switch exec(w, args) {
case 0:
// sync succeeded and some files have changed;
// update package tree.
// TODO(gri): The directory tree may be temporarily out-of-sync.
// Consider keeping separate time stamps so the web-
// page can indicate this discrepancy.
- fsTree.set(newDirectory(*goroot, maxDirDepth))
+ initFSTree()
fallthrough
case 1:
// sync failed because no files changed;
@@ -152,9 +150,9 @@ func usage() {
func loggingHandler(h http.Handler) http.Handler {
- return http.HandlerFunc(func(c *http.Conn, req *http.Request) {
- log.Stderrf("%s\t%s", c.RemoteAddr, req.URL)
- h.ServeHTTP(c, req)
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ log.Printf("%s\t%s", w.RemoteAddr(), req.URL)
+ h.ServeHTTP(w, req)
})
}
@@ -239,13 +237,16 @@ func main() {
// HTTP server mode.
var handler http.Handler = http.DefaultServeMux
if *verbose {
- log.Stderrf("Go Documentation Server\n")
- log.Stderrf("version = %s\n", runtime.Version())
- log.Stderrf("address = %s\n", *httpAddr)
- log.Stderrf("goroot = %s\n", *goroot)
- log.Stderrf("tabwidth = %d\n", *tabwidth)
+ log.Printf("Go Documentation Server")
+ log.Printf("version = %s", runtime.Version())
+ log.Printf("address = %s", *httpAddr)
+ log.Printf("goroot = %s", *goroot)
+ log.Printf("tabwidth = %d", *tabwidth)
+ if *fulltextIndex {
+ log.Print("full text index enabled")
+ }
if !fsMap.IsEmpty() {
- log.Stderr("user-defined mapping:")
+ log.Print("user-defined mapping:")
fsMap.Fprint(os.Stderr)
}
handler = loggingHandler(handler)
@@ -256,12 +257,12 @@ func main() {
http.Handle("/debug/sync", http.HandlerFunc(dosync))
}
- // Initialize directory tree with corresponding timestamp.
- // Do it in two steps:
- // 1) set timestamp right away so that the indexer is kicked on
- fsTree.set(nil)
- // 2) compute initial directory tree in a goroutine so that launch is quick
- go func() { fsTree.set(newDirectory(*goroot, maxDirDepth)) }()
+ // Initialize default directory tree with corresponding timestamp.
+ // (Do it in a goroutine so that launch is quick.)
+ go initFSTree()
+
+ // Initialize directory trees for user-defined file systems (-path flag).
+ initDirTrees()
// Start sync goroutine, if enabled.
if *syncCmd != "" && *syncMin > 0 {
@@ -271,7 +272,7 @@ func main() {
dosync(nil, nil)
delay, _ := syncDelay.get()
if *verbose {
- log.Stderrf("next sync in %dmin", delay.(int))
+ log.Printf("next sync in %dmin", delay.(int))
}
time.Sleep(int64(delay.(int)) * 60e9)
}
@@ -333,15 +334,18 @@ func main() {
}
// TODO(gri): Provide a mechanism (flag?) to select a package
// if there are multiple packages in a directory.
- info := pkgHandler.getPageInfo(abspath, relpath, "", mode|tryMode)
+ info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
- if info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
+ if info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
// try again, this time assume it's a command
if len(path) > 0 && path[0] != '/' {
abspath = absolutePath(path, cmdHandler.fsRoot)
}
info = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
+ if info.Err != nil {
+ log.Exitf("%v", info.Err)
+ }
// If we have more than one argument, use the remaining arguments for filtering
if flag.NArg() > 1 {
@@ -362,7 +366,7 @@ func main() {
if i > 0 {
fmt.Println()
}
- writeAny(os.Stdout, d, *html)
+ writeAny(os.Stdout, info.FSet, *html, d)
fmt.Println()
}
return
@@ -373,6 +377,6 @@ func main() {
}
if err := packageText.Execute(info, os.Stdout); err != nil {
- log.Stderrf("packageText.Execute: %s", err)
+ log.Printf("packageText.Execute: %s", err)
}
}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
index 400f97e1f..1d87bbc76 100644
--- a/src/cmd/godoc/mapping.go
+++ b/src/cmd/godoc/mapping.go
@@ -11,6 +11,7 @@ import (
"io"
"os"
pathutil "path"
+ "sort"
"strings"
)
@@ -42,14 +43,19 @@ import (
//
// (assuming that file exists).
//
+// Each individual mapping also has a RWValue associated with it that
+// may be used to store mapping-specific information. See the Iterate
+// method.
+//
type Mapping struct {
list []mapping
- prefixes []string
+ prefixes []string // lazily computed from list
}
type mapping struct {
prefix, path string
+ value *RWValue
}
@@ -75,43 +81,16 @@ type mapping struct {
// public -> /home/build/public
//
func (m *Mapping) Init(paths string) {
- cwd, _ := os.Getwd() // ignore errors
-
- pathlist := strings.Split(paths, ":", -1)
-
+ pathlist := canonicalizePaths(strings.Split(paths, ":", -1), nil)
list := make([]mapping, len(pathlist))
- n := 0 // number of mappings
- for _, path := range pathlist {
- if len(path) == 0 {
- // ignore empty paths (don't assume ".")
- continue
- }
-
- // len(path) > 0: normalize path
- if path[0] != '/' {
- path = pathutil.Join(cwd, path)
- } else {
- path = pathutil.Clean(path)
- }
-
- // check if mapping exists already
- var i int
- for i = 0; i < n; i++ {
- if path == list[i].path {
- break
- }
- }
-
- // add mapping if it is new
- if i >= n {
- _, prefix := pathutil.Split(path)
- list[n] = mapping{prefix, path}
- n++
- }
+ // create mapping list
+ for i, path := range pathlist {
+ _, prefix := pathutil.Split(path)
+ list[i] = mapping{prefix, path, new(RWValue)}
}
- m.list = list[0:n]
+ m.list = list
}
@@ -134,24 +113,25 @@ func (m *Mapping) PrefixList() []string {
// compute the list lazily
if m.prefixes == nil {
list := make([]string, len(m.list))
- n := 0 // nuber of prefixes
-
- for _, e := range m.list {
- // check if prefix exists already
- var i int
- for i = 0; i < n; i++ {
- if e.prefix == list[i] {
- break
- }
- }
- // add prefix if it is new
- if i >= n {
- list[n] = e.prefix
- n++
+ // populate list
+ for i, e := range m.list {
+ list[i] = e.prefix
+ }
+
+ // sort the list and remove duplicate entries
+ sort.SortStrings(list)
+ i := 0
+ prev := ""
+ for _, path := range list {
+ if path != prev {
+ list[i] = path
+ i++
+ prev = path
}
}
- m.prefixes = list[0:n]
+
+ m.prefixes = list[0:i]
}
return m.prefixes
@@ -166,7 +146,7 @@ func (m *Mapping) Fprint(w io.Writer) {
}
-func split(path string) (head, tail string) {
+func splitFirst(path string) (head, tail string) {
i := strings.Index(path, "/")
if i > 0 {
// 0 < i < len(path)
@@ -181,7 +161,7 @@ func split(path string) (head, tail string) {
// string is returned.
//
func (m *Mapping) ToAbsolute(path string) string {
- prefix, tail := split(path)
+ prefix, tail := splitFirst(path)
for _, e := range m.list {
switch {
case e.prefix == prefix:
@@ -214,3 +194,15 @@ func (m *Mapping) ToRelative(path string) string {
}
return "" // no match
}
+
+
+// Iterate calls f for each path and RWValue in the mapping (in uspecified order)
+// until f returns false.
+//
+func (m *Mapping) Iterate(f func(path string, value *RWValue) bool) {
+ for _, e := range m.list {
+ if !f(e.path, e.value) {
+ return
+ }
+ }
+}
diff --git a/src/cmd/godoc/snippet.go b/src/cmd/godoc/snippet.go
index d8fb19533..6a12febe1 100755
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -12,41 +12,22 @@ package main
import (
"bytes"
"go/ast"
- "go/printer"
+ "go/token"
"fmt"
)
type Snippet struct {
Line int
- Text string
+ Text []byte
}
-type snippetStyler struct {
- Styler // defined in godoc.go
- highlight *ast.Ident // identifier to highlight
-}
-
-
-func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HTMLTag) {
- return // no LineTag for snippets
-}
-
-
-func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
- text = []byte(id.Name())
- if s.highlight == id {
- tag = printer.HTMLTag{"<span class=highlight>", "</span>"}
- }
- return
-}
-
-
-func newSnippet(decl ast.Decl, id *ast.Ident) *Snippet {
+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, decl, true, &snippetStyler{highlight: id})
- return &Snippet{id.Pos().Line, buf.String()}
+ writeNode(&buf, fset, decl, true)
+ return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)}
}
@@ -73,20 +54,20 @@ func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
}
-func genSnippet(d *ast.GenDecl, id *ast.Ident) *Snippet {
+func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
s := findSpec(d.Specs, id)
if s == nil {
return nil // declaration doesn't contain id - exit gracefully
}
// only use the spec containing the id for the snippet
- dd := &ast.GenDecl{d.Doc, d.Position, d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
+ dd := &ast.GenDecl{d.Doc, d.Pos(), d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
- return newSnippet(dd, id)
+ return newSnippet(fset, dd, id)
}
-func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
+func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
if d.Name != id {
return nil // declaration doesn't contain id - exit gracefully
}
@@ -94,7 +75,7 @@ func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
// only use the function signature for the snippet
dd := &ast.FuncDecl{d.Doc, d.Recv, d.Name, d.Type, nil}
- return newSnippet(dd, id)
+ return newSnippet(fset, dd, id)
}
@@ -102,19 +83,21 @@ func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
// identifier id. Parts of the declaration not containing the identifier
// may be removed for a more compact snippet.
//
-func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) {
+func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) {
switch d := decl.(type) {
case *ast.GenDecl:
- s = genSnippet(d, id)
+ s = genSnippet(fset, d, id)
case *ast.FuncDecl:
- s = funcSnippet(d, id)
+ s = funcSnippet(fset, d, id)
}
// handle failure gracefully
if s == nil {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
s = &Snippet{
- id.Pos().Line,
- fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Name()),
+ fset.Position(id.Pos()).Line,
+ buf.Bytes(),
}
}
return
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index 2298fae2c..b1c1a883f 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -20,24 +20,28 @@ import (
type ebnfParser struct {
- out io.Writer // parser output
- src []byte // parser source
+ out io.Writer // parser output
+ src []byte // parser source
+ file *token.File // for position information
scanner scanner.Scanner
- prev int // offset of previous token
- pos token.Position // token position
- tok token.Token // one token look-ahead
- lit []byte // token literal
+ prev int // offset of previous token
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
}
func (p *ebnfParser) flush() {
- p.out.Write(p.src[p.prev:p.pos.Offset])
- p.prev = p.pos.Offset
+ offs := p.file.Offset(p.pos)
+ p.out.Write(p.src[p.prev:offs])
+ p.prev = offs
}
func (p *ebnfParser) next() {
- p.flush()
+ if p.pos.IsValid() {
+ p.flush()
+ }
p.pos, p.tok, p.lit = p.scanner.Scan()
if p.tok.IsKeyword() {
// TODO Should keyword mapping always happen outside scanner?
@@ -52,9 +56,9 @@ func (p *ebnfParser) Error(pos token.Position, msg string) {
}
-func (p *ebnfParser) errorExpected(pos token.Position, msg string) {
+func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
- if pos.Offset == p.pos.Offset {
+ if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
msg += ", found '" + p.tok.String() + "'"
@@ -62,11 +66,11 @@ func (p *ebnfParser) errorExpected(pos token.Position, msg string) {
msg += " " + string(p.lit)
}
}
- p.Error(pos, msg)
+ p.Error(p.file.Position(pos), msg)
}
-func (p *ebnfParser) expect(tok token.Token) token.Position {
+func (p *ebnfParser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
p.errorExpected(pos, "'"+tok.String()+"'")
@@ -148,11 +152,11 @@ func (p *ebnfParser) parseProduction() {
}
-func (p *ebnfParser) parse(out io.Writer, src []byte) {
+func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
// initialize ebnfParser
p.out = out
p.src = src
- p.scanner.Init("", src, p, 0)
+ p.file = p.scanner.Init(fset, "", src, p, 0)
p.next() // initializes pos, tok, lit
// process source
@@ -171,6 +175,7 @@ var (
func linkify(out io.Writer, src []byte) {
+ fset := token.NewFileSet()
for len(src) > 0 {
n := len(src)
@@ -192,7 +197,7 @@ func linkify(out io.Writer, src []byte) {
out.Write(src[0:i])
// parse and write EBNF
var p ebnfParser
- p.parse(out, src[i:j])
+ p.parse(fset, out, src[i:j])
// advance
src = src[j:n]
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
new file mode 100644
index 000000000..55cf87841
--- /dev/null
+++ b/src/cmd/godoc/utils.go
@@ -0,0 +1,109 @@
+// 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.
+
+// This file contains support functionality for godoc.
+
+package main
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ pathutil "path"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+)
+
+
+// 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{}
+ timestamp int64 // time of last set(), in seconds since epoch
+}
+
+
+func (v *RWValue) set(value interface{}) {
+ v.mutex.Lock()
+ v.value = value
+ v.timestamp = time.Seconds()
+ v.mutex.Unlock()
+}
+
+
+func (v *RWValue) get() (interface{}, int64) {
+ v.mutex.RLock()
+ defer v.mutex.RUnlock()
+ return v.value, v.timestamp
+}
+
+
+var cwd, _ = os.Getwd() // ignore errors
+
+// canonicalizePaths takes a list of (directory/file) paths and returns
+// the list of corresponding absolute paths in sorted (increasing) order.
+// Relative paths are assumed to be relative to the current directory,
+// empty and duplicate paths as well as paths for which filter(path) is
+// false are discarded. filter may be nil in which case it is not used.
+//
+func canonicalizePaths(list []string, filter func(path string) bool) []string {
+ i := 0
+ for _, path := range list {
+ path = strings.TrimSpace(path)
+ if len(path) == 0 {
+ continue // ignore empty paths (don't assume ".")
+ }
+ // len(path) > 0: normalize path
+ if path[0] != '/' {
+ path = pathutil.Join(cwd, path)
+ } else {
+ path = pathutil.Clean(path)
+ }
+ // we have a non-empty absolute path
+ if filter != nil && !filter(path) {
+ continue
+ }
+ // keep the path
+ list[i] = path
+ i++
+ }
+ list = list[0:i]
+
+ // sort the list and remove duplicate entries
+ sort.SortStrings(list)
+ i = 0
+ prev := ""
+ for _, path := range list {
+ if path != prev {
+ list[i] = path
+ i++
+ prev = path
+ }
+ }
+
+ return list[0:i]
+}
+
+
+// writeFileAtomically writes data to a temporary file and then
+// atomically renames that file to the file named by filename.
+//
+func writeFileAtomically(filename string, data []byte) os.Error {
+ f, err := ioutil.TempFile(cwd, filename)
+ if err != nil {
+ return err
+ }
+ n, err := f.Write(data)
+ f.Close()
+ if err != nil {
+ return err
+ }
+ if n < len(data) {
+ return io.ErrShortWrite
+ }
+ return os.Rename(f.Name(), filename)
+}
diff --git a/src/cmd/gofmt/Makefile b/src/cmd/gofmt/Makefile
index 2294fd1db..5f2f454e8 100644
--- a/src/cmd/gofmt/Makefile
+++ b/src/cmd/gofmt/Makefile
@@ -2,12 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=gofmt
GOFILES=\
gofmt.go\
rewrite.go\
+ simplify.go\
include ../../Make.cmd
@@ -15,5 +16,4 @@ test: $(TARG)
./test.sh
smoketest: $(TARG)
- ./test.sh "$(GOROOT)"/src/pkg/go/parser/parser.go
-
+ (cd testdata; ./test.sh)
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 2e4c40c21..2d2c9ae61 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -20,6 +20,8 @@ The flags are:
unless -w is also set.
-r rule
apply the rewrite rule to the source before reformatting.
+ -s
+ try to simplify code (after applying the rewrite rule, if any).
-w
if set, overwrite each input file with its output.
-spaces
@@ -33,6 +35,8 @@ Debugging flags:
-trace
print parse trace.
+ -ast
+ print AST (before rewrites).
-comments=true
print comments; if false, all comments are elided from the output.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index ffec0325f..d7b70c461 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -12,6 +12,7 @@ import (
"go/parser"
"go/printer"
"go/scanner"
+ "go/token"
"io/ioutil"
"os"
pathutil "path"
@@ -24,11 +25,12 @@ var (
list = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
write = flag.Bool("w", false, "write result to (source) file instead of stdout")
rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'α[β:len(α)] -> α[β:]')")
+ simplifyAST = flag.Bool("s", false, "simplify code")
// debugging support
comments = flag.Bool("comments", true, "print comments")
- debug = flag.Bool("debug", false, "print debugging information")
trace = flag.Bool("trace", false, "print parse trace")
+ printAST = flag.Bool("ast", false, "print AST (before rewrites)")
// layout control
tabWidth = flag.Int("tabwidth", 8, "tab width")
@@ -38,6 +40,7 @@ var (
var (
+ fset = token.NewFileSet()
exitCode = 0
rewrite func(*ast.File) *ast.File
parserMode uint
@@ -92,22 +95,26 @@ func processFile(f *os.File) os.Error {
return err
}
- var scope *ast.Scope
- if *debug {
- scope = ast.NewScope(nil)
- }
- file, err := parser.ParseFile(f.Name(), src, scope, parserMode)
+ file, err := parser.ParseFile(fset, f.Name(), src, parserMode)
if err != nil {
return err
}
+ if *printAST {
+ ast.Print(file)
+ }
+
if rewrite != nil {
file = rewrite(file)
}
+ if *simplifyAST {
+ simplify(file)
+ }
+
var res bytes.Buffer
- _, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, file)
+ _, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, fset, file)
if err != nil {
return err
}
@@ -133,10 +140,10 @@ func processFile(f *os.File) os.Error {
}
-func processFileByName(filename string) (err os.Error) {
+func processFileByName(filename string) os.Error {
file, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil {
- return
+ return err
}
defer file.Close()
return processFile(file)
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index a89146ca0..8ea5334e9 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -37,7 +37,7 @@ func initRewrite() {
// but there are problems with preserving formatting and also
// with what a wildcard for a statement looks like.
func parseExpr(s string, what string) ast.Expr {
- x, err := parser.ParseExpr("input", s, nil)
+ x, err := parser.ParseExpr(fset, "input", s)
if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
os.Exit(2)
@@ -66,13 +66,19 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
}
-var positionType = reflect.Typeof(token.Position{})
-var identType = reflect.Typeof((*ast.Ident)(nil))
-
-
-func isWildcard(s string) bool {
- rune, size := utf8.DecodeRuneInString(s)
- return size == len(s) && unicode.IsLower(rune)
+// setValue is a wrapper for x.SetValue(y); it protects
+// the caller from panics if x cannot be changed to y.
+func setValue(x, y reflect.Value) {
+ defer func() {
+ if x := recover(); x != nil {
+ if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
+ // x cannot be set to y - ignore this rewrite
+ return
+ }
+ panic(x)
+ }
+ }()
+ x.SetValue(y)
}
@@ -86,21 +92,31 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value
case *reflect.SliceValue:
for i := 0; i < v.Len(); i++ {
e := v.Elem(i)
- e.SetValue(f(e))
+ setValue(e, f(e))
}
case *reflect.StructValue:
for i := 0; i < v.NumField(); i++ {
e := v.Field(i)
- e.SetValue(f(e))
+ setValue(e, f(e))
}
case *reflect.InterfaceValue:
e := v.Elem()
- v.SetValue(f(e))
+ setValue(v, f(e))
}
return val
}
+var positionType = reflect.Typeof(token.NoPos)
+var identType = reflect.Typeof((*ast.Ident)(nil))
+
+
+func isWildcard(s string) bool {
+ rune, size := utf8.DecodeRuneInString(s)
+ return size == len(s) && unicode.IsLower(rune)
+}
+
+
// match returns true if pattern matches val,
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
@@ -109,17 +125,20 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// times in the pattern, it must match the same expression
// each time.
if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name()
+ name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) {
- if old, ok := m[name]; ok {
- return match(nil, old, val)
+ // wildcards only match expressions
+ if _, ok := val.Interface().(ast.Expr); ok {
+ if old, ok := m[name]; ok {
+ return match(nil, old, val)
+ }
+ m[name] = val
+ return true
}
- m[name] = val
- return true
}
}
- // Otherwise, the expressions must match recursively.
+ // Otherwise, pattern and val must match recursively.
if pattern == nil || val == nil {
return pattern == nil && val == nil
}
@@ -139,7 +158,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// of recursing down any further via reflection.
p := pattern.Interface().(*ast.Ident)
v := val.Interface().(*ast.Ident)
- return p == nil && v == nil || p != nil && v != nil && p.Name() == v.Name()
+ return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
}
p := reflect.Indirect(pattern)
@@ -194,7 +213,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
// Wildcard gets replaced with map value.
if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name()
+ name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) {
if old, ok := m[name]; ok {
return subst(nil, old, nil)
@@ -203,6 +222,10 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
}
if pos != nil && pattern.Type() == positionType {
+ // use new position only if old position was valid in the first place
+ if old := pattern.Interface().(token.Pos); !old.IsValid() {
+ return pattern
+ }
return pos
}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
new file mode 100644
index 000000000..bcc67c4a6
--- /dev/null
+++ b/src/cmd/gofmt/simplify.go
@@ -0,0 +1,67 @@
+// 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.
+
+package main
+
+import (
+ "go/ast"
+ "reflect"
+)
+
+
+type simplifier struct{}
+
+func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CompositeLit:
+ // array, slice, and map composite literals may be simplified
+ outer := n
+ var eltType ast.Expr
+ switch typ := outer.Type.(type) {
+ case *ast.ArrayType:
+ eltType = typ.Elt
+ case *ast.MapType:
+ eltType = typ.Value
+ }
+
+ if eltType != nil {
+ typ := reflect.NewValue(eltType)
+ for _, x := range outer.Elts {
+ // look at value of indexed/named elements
+ if t, ok := x.(*ast.KeyValueExpr); ok {
+ x = t.Value
+ }
+ simplify(x)
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.NewValue(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ }
+
+ // node was simplified - stop walk (there are no subnodes to simplify)
+ return nil
+ }
+
+ case *ast.RangeStmt:
+ // range of the form: for x, _ = range v {...}
+ // can be simplified to: for x = range v {...}
+ if n.Value != nil {
+ if ident, ok := n.Value.(*ast.Ident); ok && ident.Name == "_" {
+ n.Value = nil
+ }
+ }
+ }
+
+ return s
+}
+
+
+func simplify(node ast.Node) {
+ var s simplifier
+ ast.Walk(&s, node)
+}
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
index bed46532b..b5f4de1e2 100755
--- a/src/cmd/gofmt/test.sh
+++ b/src/cmd/gofmt/test.sh
@@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
if [ -z "$O" ]; then
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
exit 1
@@ -41,7 +41,8 @@ apply1() {
bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
- bug282.go ) return ;;
+ bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
+ bug302.go | bug306.go ) return ;;
esac
# the following directories are skipped because they contain test
# cases for syntax errors and thus won't parse in the first place:
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
new file mode 100644
index 000000000..1fd5847c1
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -0,0 +1,104 @@
+package P
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [...]T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = []T{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ {},
+ 10: {1, 2},
+ 20: {3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ {},
+ {1, 2},
+ {3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ {3, 4},
+}
+
+var _ = [][][]int{
+ {},
+ {
+ {},
+ {0, 1, 2, 3},
+ {4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": {},
+ "bar": {1, 2},
+ "bal": {3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": {3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ {0, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {1, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+ {2, 0, Point{4, 1}, []Point{{0, 0}, {1, 0}, {1, 0}, {1, 0}}, nil, nil},
+ {3, 0, Point{1, 4}, []Point{{0, 0}, {0, 1}, {0, 1}, {0, 1}}, nil, nil},
+}
diff --git a/src/cmd/gofmt/testdata/composites.input b/src/cmd/gofmt/testdata/composites.input
new file mode 100644
index 000000000..15afd9e5c
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -0,0 +1,104 @@
+package P
+
+type T struct {
+ x, y int
+}
+
+var _ = [42]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = [...]T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ T{1, 2},
+ T{3, 4},
+}
+
+var _ = []T{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = []struct {
+ x, y int
+}{
+ struct{ x, y int }{},
+ 10: struct{ x, y int }{1, 2},
+ 20: struct{ x, y int }{3, 4},
+}
+
+var _ = []interface{}{
+ T{},
+ 10: T{1, 2},
+ 20: T{3, 4},
+}
+
+var _ = [][]int{
+ []int{},
+ []int{1, 2},
+ []int{3, 4},
+}
+
+var _ = [][]int{
+ ([]int{}),
+ ([]int{1, 2}),
+ []int{3, 4},
+}
+
+var _ = [][][]int{
+ [][]int{},
+ [][]int{
+ []int{},
+ []int{0, 1, 2, 3},
+ []int{4, 5},
+ },
+}
+
+var _ = map[string]T{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string]struct {
+ x, y int
+}{
+ "foo": struct{ x, y int }{},
+ "bar": struct{ x, y int }{1, 2},
+ "bal": struct{ x, y int }{3, 4},
+}
+
+var _ = map[string]interface{}{
+ "foo": T{},
+ "bar": T{1, 2},
+ "bal": T{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": []int{},
+ "bar": []int{1, 2},
+ "bal": []int{3, 4},
+}
+
+var _ = map[string][]int{
+ "foo": ([]int{}),
+ "bar": ([]int{1, 2}),
+ "bal": []int{3, 4},
+}
+
+// from exp/4s/data.go
+var pieces4 = []Piece{
+ Piece{0, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{1, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+ Piece{2, 0, Point{4, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
+ Piece{3, 0, Point{1, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
+}
diff --git a/src/cmd/gofmt/testdata/test.sh b/src/cmd/gofmt/testdata/test.sh
new file mode 100755
index 000000000..a1d5d823e
--- /dev/null
+++ b/src/cmd/gofmt/testdata/test.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+# 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.
+
+CMD="../gofmt"
+TMP=test_tmp.go
+COUNT=0
+
+
+cleanup() {
+ rm -f $TMP
+}
+
+
+error() {
+ echo $1
+ exit 1
+}
+
+
+count() {
+ #echo $1
+ let COUNT=$COUNT+1
+ let M=$COUNT%10
+ if [ $M == 0 ]; then
+ echo -n "."
+ fi
+}
+
+
+test() {
+ count $1
+
+ # compare against .golden file
+ cleanup
+ $CMD -s $1 > $TMP
+ cmp -s $TMP $2
+ if [ $? != 0 ]; then
+ diff $TMP $2
+ error "Error: simplified $1 does not match $2"
+ fi
+
+ # make sure .golden is idempotent
+ cleanup
+ $CMD -s $2 > $TMP
+ cmp -s $TMP $2
+ if [ $? != 0 ]; then
+ diff $TMP $2
+ error "Error: $2 is not idempotent"
+ fi
+}
+
+
+runtests() {
+ smoketest=../../../pkg/go/parser/parser.go
+ test $smoketest $smoketest
+ test composites.input composites.golden
+ # add more test cases here
+}
+
+
+runtests
+cleanup
+echo "PASSED ($COUNT tests)"
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
index cf4728401..6ddb32be7 100644
--- a/src/cmd/goinstall/Makefile
+++ b/src/cmd/goinstall/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=goinstall
GOFILES=\
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index 80b30d5ac..17cc06969 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -10,14 +10,33 @@ It maintains a list of public Go packages at http://godashboard.appspot.com/pack
Usage:
goinstall [flags] importpath...
+ goinstall [flags] -a
Flags and default settings:
+ -a=false install all previously installed packages
-dashboard=true tally public packages on godashboard.appspot.com
- -update=false update already-downloaded packages
+ -log=true log installed packages to $GOROOT/goinstall.log for use by -a
+ -u=false update already-downloaded packages
-v=false verbose operation
-Goinstall installs each of the packages identified on the command line.
-It installs a package's prerequisites before trying to install the package itself.
+Goinstall installs each of the packages identified on the command line. It
+installs a package's prerequisites before trying to install the package
+itself. Unless -log=false is specified, goinstall logs the import path of each
+installed package to $GOROOT/goinstall.log for use by goinstall -a.
+
+If the -a flag is given, goinstall reinstalls all previously installed
+packages, reading the list from $GOROOT/goinstall.log. After updating to a
+new Go release, which deletes all package binaries, running
+
+ goinstall -a
+
+will recompile and reinstall goinstalled packages.
+
+Another common idiom is to use
+
+ goinstall -a -u
+
+to update, recompile, and reinstall all goinstalled packages.
The source code for a package with import path foo/bar is expected
to be in the directory $GOROOT/src/pkg/foo/bar/. If the import
@@ -31,8 +50,8 @@ if necessary. The recognized code hosting sites are:
GitHub (Git)
- import "github.com/user/project.git"
- import "github.com/user/project.git/sub/directory"
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
Google Code Project Hosting (Mercurial, Subversion)
@@ -44,17 +63,17 @@ if necessary. The recognized code hosting sites are:
Launchpad
- import "launchpad.net/project
- import "launchpad.net/project/series
- import "launchpad.net/project/series/sub/directory
+ import "launchpad.net/project"
+ import "launchpad.net/project/series"
+ import "launchpad.net/project/series/sub/directory"
- import "launchpad.net/~user/project/branch
- import "launchpad.net/~user/project/branch/sub/directory
+ import "launchpad.net/~user/project/branch"
+ import "launchpad.net/~user/project/branch/sub/directory"
If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
-attempt to fetch updates. The -update flag changes this behavior,
+attempt to fetch updates. The -u flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index 3422e8186..889f9d857 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -38,16 +38,16 @@ var launchpad = regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A
// download checks out or updates pkg from the remote server.
func download(pkg string) (string, os.Error) {
- if strings.Index(pkg, "..") >= 0 {
+ if strings.Contains(pkg, "..") {
return "", os.ErrorString("invalid path (contains ..)")
}
- if m := bitbucket.MatchStrings(pkg); m != nil {
+ if m := bitbucket.FindStringSubmatch(pkg); m != nil {
if err := vcsCheckout(&hg, root+m[1], "http://"+m[1], m[1]); err != nil {
return "", err
}
return root + pkg, nil
}
- if m := googlecode.MatchStrings(pkg); m != nil {
+ if m := googlecode.FindStringSubmatch(pkg); m != nil {
var v *vcs
switch m[2] {
case "hg":
@@ -58,12 +58,12 @@ func download(pkg string) (string, os.Error) {
// regexp only allows hg, svn to get through
panic("missing case in download: " + pkg)
}
- if err := vcsCheckout(v, root+m[1], "http://"+m[1], m[1]); err != nil {
+ if err := vcsCheckout(v, root+m[1], "https://"+m[1], m[1]); err != nil {
return "", err
}
return root + pkg, nil
}
- if m := github.MatchStrings(pkg); m != nil {
+ if m := github.FindStringSubmatch(pkg); m != nil {
if strings.HasSuffix(m[1], ".git") {
return "", os.ErrorString("repository " + pkg + " should not have .git suffix")
}
@@ -72,7 +72,7 @@ func download(pkg string) (string, os.Error) {
}
return root + pkg, nil
}
- if m := launchpad.MatchStrings(pkg); m != nil {
+ if m := launchpad.FindStringSubmatch(pkg); m != nil {
// Either lp.net/<project>[/<series>[/<path>]]
// or lp.net/~<user or team>/<project>/<branch>[/<path>]
if err := vcsCheckout(&bzr, root+m[1], "https://"+m[1], m[1]); err != nil {
@@ -88,6 +88,7 @@ func download(pkg string) (string, os.Error) {
type vcs struct {
cmd string
metadir string
+ checkout string
clone string
update string
updateReleaseFlag string
@@ -101,6 +102,7 @@ type vcs struct {
var hg = vcs{
cmd: "hg",
metadir: ".hg",
+ checkout: "checkout",
clone: "clone",
update: "update",
updateReleaseFlag: "release",
@@ -113,18 +115,20 @@ var hg = vcs{
var git = vcs{
cmd: "git",
metadir: ".git",
+ checkout: "checkout",
clone: "clone",
update: "pull",
updateReleaseFlag: "release",
pull: "fetch",
- log: "log",
- logLimitFlag: "-n1",
+ log: "show-ref",
+ logLimitFlag: "",
logReleaseFlag: "release",
}
var svn = vcs{
cmd: "svn",
metadir: ".svn",
+ checkout: "checkout",
clone: "checkout",
update: "update",
updateReleaseFlag: "release",
@@ -136,6 +140,7 @@ var svn = vcs{
var bzr = vcs{
cmd: "bzr",
metadir: ".bzr",
+ checkout: "update",
clone: "branch",
update: "update",
updateReleaseFlag: "-rrelease",
@@ -146,6 +151,22 @@ var bzr = vcs{
logReleaseFlag: "-rrelease",
}
+// Try to detect if a "release" tag exists. If it does, update
+// to the tagged version, otherwise just update the current branch.
+// NOTE(_nil): svn will always fail because it is trying to get
+// the revision history of a file named "release" instead of
+// looking for a commit with a release tag
+func (v *vcs) updateRepo(dst string) os.Error {
+ if err := quietRun(dst, nil, v.cmd, v.log, v.logLimitFlag, v.logReleaseFlag); err == nil {
+ if err := run(dst, nil, v.cmd, v.checkout, v.updateReleaseFlag); err != nil {
+ return err
+ }
+ } else if err := run(dst, nil, v.cmd, v.update); err != nil {
+ return err
+ }
+ return nil
+}
+
// vcsCheckout checks out repo into dst using vcs.
// It tries to check out (or update, if the dst already
// exists and -u was specified on the command line)
@@ -164,8 +185,9 @@ func vcsCheckout(vcs *vcs, dst, repo, dashpath string) os.Error {
if err := run("/", nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
return err
}
- quietRun(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag)
-
+ if err := vcs.updateRepo(dst); err != nil {
+ return err
+ }
// success on first installation - report
maybeReportToDashboard(dashpath)
} else if *update {
@@ -181,19 +203,8 @@ func vcsCheckout(vcs *vcs, dst, repo, dashpath string) os.Error {
}
}
- // Try to detect if a "release" tag exists. If it does, update
- // to the tagged version. If no tag is found, then update to the
- // tip afterwards.
- // NOTE(gustavo@niemeyer.net): What is the expected behavior with
- // svn here? "svn log -l1 release" doesn't make sense in this
- // context and will probably fail.
- if err := quietRun(dst, nil, vcs.cmd, vcs.log, vcs.logLimitFlag, vcs.logReleaseFlag); err == nil {
- if err := run(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag); err != nil {
- // The VCS supports tagging, has the "release" tag, but
- // something else went wrong. Report.
- return err
- }
- } else if err := run(dst, nil, vcs.cmd, vcs.update); err != nil {
+ // Update to release or latest revision
+ if err := vcs.updateRepo(dst); err != nil {
return err
}
}
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index 60efdf082..b0f08efdf 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -11,28 +11,37 @@ import (
"exec"
"flag"
"fmt"
+ "go/token"
"io"
+ "io/ioutil"
"os"
"path"
+ "runtime"
"strings"
)
func usage() {
fmt.Fprint(os.Stderr, "usage: goinstall importpath...\n")
+ fmt.Fprintf(os.Stderr, "\tgoinstall -a\n")
flag.PrintDefaults()
os.Exit(2)
}
var (
- argv0 = os.Args[0]
- errors = false
- gobin = os.Getenv("GOBIN")
- parents = make(map[string]string)
- root = os.Getenv("GOROOT")
- visit = make(map[string]status)
+ fset = token.NewFileSet()
+ argv0 = os.Args[0]
+ errors = false
+ parents = make(map[string]string)
+ root = runtime.GOROOT()
+ visit = make(map[string]status)
+ logfile = path.Join(root, "goinstall.log")
+ installedPkgs = make(map[string]bool)
+ allpkg = flag.Bool("a", false, "install all previously installed packages")
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
+ logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
update = flag.Bool("u", false, "update already-downloaded packages")
+ clean = flag.Bool("clean", false, "clean the package directory before installing")
verbose = flag.Bool("v", false, "verbose")
)
@@ -51,15 +60,30 @@ func main() {
os.Exit(1)
}
root += "/src/pkg/"
- if gobin == "" {
- gobin = os.Getenv("HOME") + "/bin"
- }
// special case - "unsafe" is already installed
visit["unsafe"] = done
- // install command line arguments
args := flag.Args()
+ if *allpkg || *logPkgs {
+ readPackageList()
+ }
+ if *allpkg {
+ if len(args) != 0 {
+ usage() // -a and package list both provided
+ }
+ // install all packages that were ever installed
+ if len(installedPkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0)
+ os.Exit(1)
+ }
+ args = make([]string, len(installedPkgs), len(installedPkgs))
+ i := 0
+ for pkg := range installedPkgs {
+ args[i] = pkg
+ i++
+ }
+ }
if len(args) == 0 {
usage()
}
@@ -82,6 +106,29 @@ func printDeps(pkg string) {
fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
}
+// readPackageList reads the list of installed packages from goinstall.log
+func readPackageList() {
+ pkglistdata, _ := ioutil.ReadFile(logfile)
+ pkglist := strings.Fields(string(pkglistdata))
+ for _, pkg := range pkglist {
+ installedPkgs[pkg] = true
+ }
+}
+
+// logPackage logs the named package as installed in goinstall.log, if the package is not found in there
+func logPackage(pkg string) {
+ if installedPkgs[pkg] {
+ return
+ }
+ fout, err := os.Open(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREAT, 0644)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err)
+ return
+ }
+ fmt.Fprintf(fout, "%s\n", pkg)
+ fout.Close()
+}
+
// install installs the package named by path, which is needed by parent.
func install(pkg, parent string) {
// Make sure we're not already trying to install pkg.
@@ -104,6 +151,11 @@ func install(pkg, parent string) {
// If remote, download or update it.
var dir string
local := false
+ if strings.HasPrefix(pkg, "http://") {
+ fmt.Fprintf(os.Stderr, "%s: %s: 'http://' used in remote path, try '%s'\n", argv0, pkg, pkg[7:])
+ errors = true
+ return
+ }
if isLocalPath(pkg) {
dir = pkg
local = true
@@ -122,23 +174,25 @@ func install(pkg, parent string) {
}
// Install prerequisites.
- files, m, pkgname, err := goFiles(dir, parent == "")
+ dirInfo, err := scanDir(dir, parent == "")
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
errors = true
visit[pkg] = done
return
}
- if len(files) == 0 {
+ if len(dirInfo.goFiles) == 0 {
fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg)
errors = true
visit[pkg] = done
return
}
- for p := range m {
- install(p, pkg)
+ for _, p := range dirInfo.imports {
+ if p != "C" {
+ install(p, pkg)
+ }
}
- if pkgname == "main" {
+ if dirInfo.pkgName == "main" {
if !errors {
fmt.Fprintf(os.Stderr, "%s: %s's dependencies are installed.\n", argv0, pkg)
}
@@ -152,9 +206,11 @@ func install(pkg, parent string) {
if err := domake(dir, pkg, local); err != nil {
fmt.Fprintf(os.Stderr, "%s: installing %s: %s\n", argv0, pkg, err)
errors = true
+ } else if !local && *logPkgs {
+ // mark this package as installed in $GOROOT/goinstall.log
+ logPackage(pkg)
}
}
-
visit[pkg] = done
}
@@ -207,6 +263,9 @@ func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error {
io.Copy(&buf, p.Stdout)
w, err := p.Wait(0)
p.Close()
+ if err != nil {
+ return err
+ }
if !w.Exited() || w.ExitStatus() != 0 {
if !quiet || *verbose {
if dir != "" {
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index c15709b31..93a648b2b 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -17,30 +17,65 @@ import (
// For non-local packages or packages without Makefiles,
// domake generates a standard Makefile and passes it
// to make on standard input.
-func domake(dir, pkg string, local bool) os.Error {
+func domake(dir, pkg string, local bool) (err os.Error) {
+ needMakefile := true
if local {
_, err := os.Stat(dir + "/Makefile")
if err == nil {
- return run(dir, nil, gobin+"/gomake", "install")
+ needMakefile = false
}
}
- makefile, err := makeMakefile(dir, pkg)
- if err != nil {
- return err
+ cmd := []string{"gomake"}
+ var makefile []byte
+ if needMakefile {
+ if makefile, err = makeMakefile(dir, pkg); err != nil {
+ return err
+ }
+ cmd = append(cmd, "-f-")
+ }
+ if *clean {
+ cmd = append(cmd, "clean")
}
- return run(dir, makefile, gobin+"/gomake", "-f-", "install")
+ cmd = append(cmd, "install")
+ return run(dir, makefile, cmd...)
}
// makeMakefile computes the standard Makefile for the directory dir
// installing as package pkg. It includes all *.go files in the directory
// except those in package main and those ending in _test.go.
func makeMakefile(dir, pkg string) ([]byte, os.Error) {
- files, _, _, err := goFiles(dir, false)
+ dirInfo, err := scanDir(dir, false)
if err != nil {
return nil, err
}
+
+ if len(dirInfo.cgoFiles) == 0 && len(dirInfo.cFiles) > 0 {
+ // When using cgo, .c files are compiled with gcc. Without cgo,
+ // they may be intended for 6c. Just error out for now.
+ return nil, os.ErrorString("C files found in non-cgo package")
+ }
+
+ cgoFiles := dirInfo.cgoFiles
+ isCgo := make(map[string]bool, len(cgoFiles))
+ for _, file := range cgoFiles {
+ isCgo[file] = true
+ }
+
+ oFiles := make([]string, 0, len(dirInfo.cFiles))
+ for _, file := range dirInfo.cFiles {
+ oFiles = append(oFiles, file[:len(file)-2]+".o")
+ }
+
+ goFiles := make([]string, 0, len(dirInfo.goFiles))
+ for _, file := range dirInfo.goFiles {
+ if !isCgo[file] {
+ goFiles = append(goFiles, file)
+ }
+ }
+
var buf bytes.Buffer
- if err := makefileTemplate.Execute(&makedata{pkg, files}, &buf); err != nil {
+ md := makedata{pkg, goFiles, cgoFiles, oFiles}
+ if err := makefileTemplate.Execute(&md, &buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
@@ -48,19 +83,38 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) {
// makedata is the data type for the makefileTemplate.
type makedata struct {
- pkg string // package import path
- files []string // list of .go files
+ Pkg string // package import path
+ GoFiles []string // list of non-cgo .go files
+ CgoFiles []string // list of cgo .go files
+ OFiles []string // list of ofiles for cgo
}
var makefileTemplate = template.MustParse(`
-include $(GOROOT)/src/Make.$(GOARCH)
+include $(GOROOT)/src/Make.inc
+
+TARG={Pkg}
-TARG={pkg}
+{.section GoFiles}
GOFILES=\
-{.repeated section files}
+{.repeated section GoFiles}
+ {@}\
+{.end}
+
+{.end}
+{.section CgoFiles}
+CGOFILES=\
+{.repeated section CgoFiles}
{@}\
{.end}
+{.end}
+{.section OFiles}
+CGO_OFILES=\
+{.repeated section OFiles}
+ {@}\
+{.end}
+
+{.end}
include $(GOROOT)/src/Make.pkg
`,
nil)
diff --git a/src/cmd/goinstall/parse.go b/src/cmd/goinstall/parse.go
index ae391ed9a..679edfabc 100644
--- a/src/cmd/goinstall/parse.go
+++ b/src/cmd/goinstall/parse.go
@@ -16,36 +16,60 @@ import (
"go/parser"
)
-// goFiles returns a list of the *.go source files in dir, excluding
-// those in package main (unless allowMain is true) or ending in
-// _test.go. It also returns a map giving the packages imported by
-// those files, and the package name.
-// The map keys are the imported paths. The key's value
-// is one file that imports that path.
-func goFiles(dir string, allowMain bool) (files []string, imports map[string]string, pkgName string, err os.Error) {
+
+type dirInfo struct {
+ goFiles []string // .go files within dir (including cgoFiles)
+ cgoFiles []string // .go files that import "C"
+ cFiles []string // .c files within dir
+ imports []string // All packages imported by goFiles
+ pkgName string // Name of package within dir
+}
+
+// scanDir returns a structure with details about the Go content found
+// in the given directory. The list of files will NOT contain the
+// following entries:
+//
+// - Files in package main (unless allowMain is true)
+// - Files ending in _test.go
+// - Files starting with _ (temporary)
+// - Files containing .cgo in their names
+//
+// The imports map keys are package paths imported by listed Go files,
+// and the values are the Go files importing the respective package paths.
+func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) {
f, err := os.Open(dir, os.O_RDONLY, 0)
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
dirs, err := f.Readdir(-1)
f.Close()
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
- files = make([]string, 0, len(dirs))
- imports = make(map[string]string)
+ goFiles := make([]string, 0, len(dirs))
+ cgoFiles := make([]string, 0, len(dirs))
+ cFiles := make([]string, 0, len(dirs))
+ importsm := make(map[string]bool)
+ pkgName := ""
for i := range dirs {
d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 {
+ continue
+ }
+ if strings.HasSuffix(d.Name, ".c") {
+ cFiles = append(cFiles, d.Name)
+ continue
+ }
if !strings.HasSuffix(d.Name, ".go") || strings.HasSuffix(d.Name, "_test.go") {
continue
}
filename := path.Join(dir, d.Name)
- pf, err := parser.ParseFile(filename, nil, nil, parser.ImportsOnly)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
- s := string(pf.Name.Name())
+ s := string(pf.Name.Name)
if s == "main" && !allowMain {
continue
}
@@ -56,24 +80,31 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str
// do we return pkgName=="main".
// A mix of main and another package reverts
// to the original (allowMain=false) behaviour.
- if allowMain && pkgName == "main" {
- return goFiles(dir, false)
+ if s == "main" || pkgName == "main" {
+ return scanDir(dir, false)
}
- return nil, nil, "", os.ErrorString("multiple package names in " + dir)
+ return nil, os.ErrorString("multiple package names in " + dir)
}
- n := len(files)
- files = files[0 : n+1]
- files[n] = filename
+ goFiles = append(goFiles, d.Name)
for _, decl := range pf.Decls {
for _, spec := range decl.(*ast.GenDecl).Specs {
quoted := string(spec.(*ast.ImportSpec).Path.Value)
unquoted, err := strconv.Unquote(quoted)
if err != nil {
- log.Crashf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ importsm[unquoted] = true
+ if unquoted == "C" {
+ cgoFiles = append(cgoFiles, d.Name)
}
- imports[unquoted] = filename
}
}
}
- return files, imports, pkgName, nil
+ imports := make([]string, len(importsm))
+ i := 0
+ for p := range importsm {
+ imports[i] = p
+ i++
+ }
+ return &dirInfo{goFiles, cgoFiles, cFiles, imports, pkgName}, nil
}
diff --git a/src/cmd/gomake/doc.go b/src/cmd/gomake/doc.go
new file mode 100644
index 000000000..2f35fd9dd
--- /dev/null
+++ b/src/cmd/gomake/doc.go
@@ -0,0 +1,36 @@
+// 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.
+
+/*
+The gomake command runs GNU make with an appropriate environment
+for using the conventional Go makefiles. If $GOROOT is already
+set in the environment, running gomake is exactly the same
+as running make (or, on BSD systems, running gmake).
+
+Usage: gomake [ target ... ]
+
+Common targets are:
+
+ all (default)
+ build the package or command, but do not install it.
+
+ install
+ build and install the package or command
+
+ test
+ run the tests (packages only)
+
+ bench
+ run benchmarks (packages only)
+
+ clean
+ remove object files from the current directory
+
+ nuke
+ make clean and remove the installed package or command
+
+See http://golang.org/doc/code.html for information about
+writing makefiles.
+*/
+package documentation
diff --git a/src/cmd/gopack/Makefile b/src/cmd/gopack/Makefile
index c3c136f42..859809562 100644
--- a/src/cmd/gopack/Makefile
+++ b/src/cmd/gopack/Makefile
@@ -2,17 +2,14 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
TARG=gopack
OFILES=\
ar.$O\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index 377366ec4..063967bd7 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -593,25 +593,43 @@ scanobj(Biobuf *b, Arfile *ap, long size)
vlong offset;
Dir *d;
static int lastobj = -1;
+ uchar buf[4];
if (!allobj) /* non-object file encountered */
return;
offset = Boffset(b);
obj = objtype(b, 0);
if (obj < 0) { /* not an object file */
+ /* maybe a foreign object file */
+ Bseek(b, offset, 0);
+ memset(buf, 0, sizeof buf);
+ Bread(b, buf, 4);
+
+ /* maybe a foreign object file? that's okay */
+ if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF
+ (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);
+ return;
+ }
+
if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */
fprint(2, "gopack: non-object file %s\n", file);
+ errors++;
allobj = 0;
}
d = dirfstat(Bfildes(b));
- if (d != nil && d->length == 0)
+ if (d != nil && d->length == 0) {
fprint(2, "gopack: zero length file %s\n", file);
+ errors++;
+ }
free(d);
Bseek(b, offset, 0);
return;
}
if (lastobj >= 0 && obj != lastobj) {
fprint(2, "gopack: inconsistent object file %s\n", file);
+ errors++;
allobj = 0;
Bseek(b, offset, 0);
return;
@@ -619,6 +637,7 @@ scanobj(Biobuf *b, Arfile *ap, long size)
lastobj = obj;
if (!readar(b, obj, offset+size, 0)) {
fprint(2, "gopack: invalid symbol reference in file %s\n", file);
+ errors++;
allobj = 0;
Bseek(b, offset, 0);
return;
@@ -718,8 +737,8 @@ foundstart:
first = 1;
start = end = 0;
for (n=0; n<size; n+=Blinelen(b)) {
- line = Brdline(b, '\n');
- if (line == 0)
+ line = Brdstr(b, '\n', 0);
+ if (line == nil)
goto bad;
if (first && strstrn(line, Blinelen(b), "package ")) {
if (Blinelen(b) > sizeof(pkgbuf)-1)
@@ -742,14 +761,19 @@ foundstart:
safe = 0;
start = Boffset(b); // after package statement
first = 0;
+ free(line);
continue;
}
- if(line[0] == '$' && line[1] == '$')
+ if(line[0] == '$' && line[1] == '$') {
+ free(line);
goto foundend;
+ }
end = Boffset(b); // before closing $$
+ free(line);
}
bad:
fprint(2, "gopack: bad package import section in %s\n", file);
+ errors++;
return;
foundend:
@@ -795,6 +819,7 @@ objsym(Sym *s, void *p)
if(s->type == 'T' && duplicate(as->name, &ofile)) {
dupfound = 1;
fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
+ errors++;
free(as->name);
free(as);
return;
diff --git a/src/cmd/gopack/doc.go b/src/cmd/gopack/doc.go
index 0d5ccdb6c..74c272fd2 100644
--- a/src/cmd/gopack/doc.go
+++ b/src/cmd/gopack/doc.go
@@ -4,7 +4,7 @@
/*
-Gopack program is a variant of the Plan 9 ar tool. The original is documented at
+Gopack is a variant of the Plan 9 ar tool. The original is documented at
http://plan9.bell-labs.com/magic/man2html/1/ar
diff --git a/src/cmd/gotest/Makefile b/src/cmd/gotest/Makefile
index b20b1daff..74054e974 100644
--- a/src/cmd/gotest/Makefile
+++ b/src/cmd/gotest/Makefile
@@ -1,14 +1,18 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# 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 ../../Make.conf
+include ../../Make.inc
-TARG=gotest
+TARG=install
clean:
@true
-install: $(TARG)
- ! test -f "$(GOBIN)"/$(TARG) || chmod u+w "$(GOBIN)"/$(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+install: install-gotest install-gotry
+
+install-%: %
+ ! test -f "$(GOBIN)"/$* || chmod u+w "$(GOBIN)"/$*
+ sed 's`@@GOROOT@@`$(GOROOT_FINAL)`' $* >"$(GOBIN)"/$*
+ chmod +x "$(GOBIN)"/$*
+
diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest
index fec2b4a4a..7572610d2 100755
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -3,10 +3,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# Using all the test*.go files in the current directory, write out a file
+# Using all the *_test.go files in the current directory, write out a file
# _testmain.go that runs all its tests. Compile everything and run the
# tests.
-# If files are named on the command line, use them instead of test*.go.
+# If files are named on the command line, use them instead of *_test.go.
# Makes egrep,grep work better in general if we put them
# in ordinary C mode instead of what the current language is.
@@ -14,16 +14,15 @@ unset LANG
export LC_ALL=C
export LC_CTYPE=C
-GOBIN="${GOBIN:-$HOME/bin}"
-
-_GC=$GC # Make.$GOARCH will overwrite this
+_GC=$GC # Make.inc will overwrite this
if [ ! -f [Mm]akefile ]; then
echo 'please create a Makefile for gotest; see http://golang.org/doc/code.html for details' 1>&2
exit 2
fi
-. "$GOROOT"/src/Make.$GOARCH
+export GOROOT=${GOROOT:-"@@GOROOT@@"}
+eval $(gomake -j1 --no-print-directory -f "$GOROOT"/src/Make.inc go-env)
if [ -z "$O" ]; then
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
exit 2
@@ -31,18 +30,12 @@ fi
E="$GORUN"
-# TODO(kaib): proper emulator strategy
-case x"$GOARCH" in
-xarm)
- export E=${GORUN:-qemu-arm -cpu cortex-a8}
-esac
-
# Allow overrides
-GC="$GOBIN/${_GC:-$GC} -I _test"
-GL="$GOBIN/${GL:-$LD} -L _test"
-AS="$GOBIN/$AS"
-CC="$GOBIN/$CC"
-LD="$GOBIN/$LD"
+GC="${_GC:-$GC} -I _test"
+GL="${GL:-$LD} -L _test"
+AS="$AS"
+CC="$CC"
+LD="$LD"
export GC GL O AS CC LD
gofiles=""
@@ -93,14 +86,13 @@ fi
set -e
-"$GOBIN"/gomake testpackage-clean
-"$GOBIN"/gomake testpackage "GOTESTFILES=$gofiles"
+gomake testpackage-clean
+gomake testpackage "GOTESTFILES=$gofiles"
if $havex; then
$GC -o $xofile $xgofiles
fi
# They all compile; now generate the code to call them.
-trap "rm -f _testmain.go _testmain.$O" 0 1 2 3 14 15
# Suppress output to stdout on Linux
MAKEFLAGS=
@@ -116,18 +108,18 @@ nmgrep() {
# Figure out pkg.
case "$i" in
*.a)
- pkg=$("$GOBIN"/gopack p $i __.PKGDEF | sed -n 's/^package //p' | sed 's/ .*//' | sed 1q)
+ pkg=$(gopack p $i __.PKGDEF | sed -n 's/^package //p' | sed 's/ .*//' | sed 1q)
;;
*)
pkg=$(sed -n 's/^ .* in package "\(.*\)".*/\1/p' $i | sed 1q)
;;
esac
- "$GOBIN"/6nm -s "$i" | egrep ' T .*\.'"$pat"'$' |
+ 6nm -s "$i" | egrep ' T .*\.'"$pat"'$' |
sed 's/.* //; /\..*\./d; s/""\./'"$pkg"'./g'
done
}
-importpath=$("$GOBIN"/gomake -s importpath)
+importpath=$(gomake -s importpath)
{
# test functions are named TestFoo
# the grep -v eliminates methods and other special names
@@ -155,30 +147,43 @@ importpath=$("$GOBIN"/gomake -s importpath)
echo 'import "./_xtest_"'
fi
echo 'import "testing"'
+ echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
# test array
echo
- echo 'var tests = []testing.Test {'
+ echo 'var tests = []testing.InternalTest{'
for i in $tests
do
- echo ' testing.Test{ "'$i'", '$i' },'
+ echo ' {"'$i'", '$i'},'
done
echo '}'
# benchmark array
- echo 'var benchmarks = []testing.Benchmark {'
- for i in $benchmarks
- do
- echo ' testing.Benchmark{ "'$i'", '$i' },'
- done
- echo '}'
-
+ if [ "$benchmarks" = "" ]
+ then
+ # keep the empty array gofmt-safe.
+ # (not an issue for the test array, which is never empty.)
+ echo 'var benchmarks = []testing.InternalBenchmark{}'
+ else
+ echo 'var benchmarks = []testing.InternalBenchmark{'
+ for i in $benchmarks
+ do
+ echo ' {"'$i'", '$i'},'
+ done
+ echo '}'
+ fi
# body
echo
echo 'func main() {'
- echo ' testing.Main(tests);'
- echo ' testing.RunBenchmarks(benchmarks)'
+ echo ' testing.Main(__regexp__.MatchString, tests)'
+ echo ' testing.RunBenchmarks(__regexp__.MatchString, benchmarks)'
echo '}'
}>_testmain.go
$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/gotest/gotry b/src/cmd/gotest/gotry
new file mode 100755
index 000000000..52c5d2d58
--- /dev/null
+++ b/src/cmd/gotest/gotry
@@ -0,0 +1,167 @@
+#!/usr/bin/env bash
+# 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.
+
+# Using all the non-test *.go files in the named directory, write
+# out a file /tmp/$USER.try.go to evaluate the expressions on the
+# command line, perhaps to discover a function or method that
+# gives the desired results. See usage message.
+# Compile the program and run it.
+
+# Makes egrep,grep work better in general if we put them
+# in ordinary C mode instead of what the current language is.
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+export GOROOT=${GOROOT:-"@@GOROOT@@"}
+eval $(gomake -j1 --no-print-directory -f "$GOROOT"/src/Make.inc go-env)
+if [ -z "$O" ]; then
+ echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
+ exit 2
+fi
+
+# Allow overrides
+GC="${_GC:-$GC} -I _test"
+GL="${GL:-$LD} -L _test"
+AS="$AS"
+CC="$CC"
+LD="$LD"
+export GC GL O AS CC LD
+
+# Macros for tab and quotes for easier readability.
+T=' '
+BQ='`'
+SQ="'"
+DQ='"'
+SD="$SQ$DQ"
+DS="$DQ$SQ"
+
+usage="usage: gotry [packagedirectory] expression ...
+Given one expression, gotry attempts to evaluate that expression.
+Given multiple expressions, gotry treats them as a list of arguments
+and result values and attempts to find a function in the package
+that, given the first few expressions as arguments, evaluates to
+the remaining expressions as results. If the first expression has
+methods, it will also search for applicable methods.
+
+If there are multiple expressions, a package directory must be
+specified. If there is a package argument, the expressions are
+evaluated in an environment that includes
+ import . ${DQ}packagedirectory${DQ}
+
+Examples:
+ gotry 3+4
+ # evaluates to 7
+ gotry strings ${SD}abc${DS} ${SD}c${DS} 7-5
+ # finds strings.Index etc.
+ gotry regexp ${SQ}MustCompile(${DQ}^[0-9]+${DQ})${SQ} ${SD}12345${DS} true
+ # finds Regexp.MatchString
+
+"
+
+function fail() {
+ echo 2>&1 "$@"
+ exit 2
+}
+
+case $# in
+ 0)
+ fail "$usage"
+ ;;
+ *)
+ case "$1" in
+ -*help|-*'?'|'?')
+ fail "$usage"
+ esac
+ if test -d "$GOROOT/src/pkg/$1"
+ then
+ pkg=$(basename $1)
+ dir=$GOROOT/src/pkg/$1
+ importdir=$1
+ shift
+ case "$pkg" in
+ os|syscall)
+ fail "gotry: cannot try packages os or syscall; they are too dangerous"
+ esac
+ fi
+ ;;
+esac
+
+spaces='[ ][ ]*'
+
+function getFunctions() {
+ if [ "$pkg" = "" ]
+ then
+ return
+ fi
+ for file in $dir/*.go
+ do
+ case $file in
+ *_test*)
+ continue
+ esac
+ grep "func$spaces[A-Z]" $file | # TODO: should be Unicode upper case
+ sed "s/func$spaces//;s/(.*//"
+ done | sort -u
+}
+
+# Generate list of public functions.
+functions=$(getFunctions)
+
+# Write file to compile
+rm -f /tmp/$USER.try.go
+(
+cat <<'!'
+package main
+
+import (
+ "os"
+ "try"
+!
+
+if [ "$pkg" != "" ]
+then
+ echo "$T" . '"'$importdir'"'
+fi
+
+cat <<!
+)
+func main() {
+ try.Main("$pkg", firstArg, functions, args)
+}
+var functions = map[string] interface{}{
+!
+
+for i in $functions
+do
+ echo "$T"'"'$i'": '$i','
+done
+echo "}"
+
+echo 'var args = []interface{}{'
+
+if [ $# = 1 ]
+then
+ echo "${T}toSlice($1)",
+else
+for i
+ do
+ echo "$T$i",
+ done
+fi
+echo "}"
+
+cat <<!
+var firstArg = $BQ$1$BQ
+var _ os.Error
+func toSlice(a ...interface{}) []interface{} { return a }
+!
+
+)>/tmp/$USER.try.go
+
+$GC -o /tmp/$USER.try.$O /tmp/$USER.try.go &&
+$GL -o /tmp/$USER.try /tmp/$USER.try.$O &&
+/tmp/$USER.try "_$@"
+rm -f /tmp/$USER.try /tmp/$USER.try.go /tmp/$USER.try.$O
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
new file mode 100644
index 000000000..291b27197
--- /dev/null
+++ b/src/cmd/govet/Makefile
@@ -0,0 +1,11 @@
+# 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 ../../Make.inc
+
+TARG=govet
+GOFILES=\
+ govet.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/govet/doc.go b/src/cmd/govet/doc.go
new file mode 100644
index 000000000..5a2489fca
--- /dev/null
+++ b/src/cmd/govet/doc.go
@@ -0,0 +1,38 @@
+// 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.
+
+/*
+
+Govet does simple checking of Go source code.
+
+It checks for simple errors in calls to functions named
+ Print Printf Println
+ Fprint Fprintf Fprintln
+ Sprint Sprintf Sprintln
+ Error Errorf
+ Fatal Fatalf
+If the function name ends with an 'f', the function is assumed to take
+a format descriptor string in the manner of fmt.Printf. If not, govet
+complains about arguments that look like format descriptor strings.
+
+Usage:
+
+ govet [flag] [file.go ...]
+ govet [flag] [directory ...] # Scan all .go files under directory, recursively
+
+The flags are:
+ -v
+ Verbose mode
+ -printfuncs
+ A comma-separated list of print-like functions to supplement
+ the standard list. Each entry is in the form Name:N where N
+ is the zero-based argument position of the first argument
+ involved in the print: either the format or the first print
+ argument for non-formatted prints. For example,
+ if you have Warn and Warnf functions that take an
+ io.Writer as their first argument, like Fprintf,
+ -printfuncs=Warn:1,Warnf:1
+
+*/
+package documentation
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
new file mode 100644
index 000000000..2981891eb
--- /dev/null
+++ b/src/cmd/govet/govet.go
@@ -0,0 +1,325 @@
+// 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.
+
+// Govet is a simple checker for static errors in Go source code.
+// See doc.go for more information.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path"
+ "strconv"
+ "strings"
+)
+
+var verbose = flag.Bool("v", false, "verbose")
+var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
+var exitCode = 0
+
+// setExit sets the value for os.Exit when it is called, later. It
+// remembers the highest value.
+func setExit(err int) {
+ if err > exitCode {
+ exitCode = err
+ }
+}
+
+// Usage is a replacement usage function for the flags package.
+func Usage() {
+ fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The parse tree walkers are all methods of this type.
+type File struct {
+ file *token.File
+}
+
+func main() {
+ flag.Usage = Usage
+ flag.Parse()
+
+ if *printfuncs != "" {
+ for _, name := range strings.Split(*printfuncs, ",", -1) {
+ if len(name) == 0 {
+ flag.Usage()
+ }
+ skip := 0
+ if colon := strings.LastIndex(name, ":"); colon > 0 {
+ var err os.Error
+ skip, err = strconv.Atoi(name[colon+1:])
+ if err != nil {
+ error(`illegal format for "Func:N" argument %q; %s`, name, err)
+ }
+ name = name[:colon]
+ }
+ if name[len(name)-1] == 'f' {
+ printfList[name] = skip
+ } else {
+ printList[name] = skip
+ }
+ }
+ }
+
+ if flag.NArg() == 0 {
+ doFile("stdin", os.Stdin)
+ } else {
+ for _, name := range flag.Args() {
+ // Is it a directory?
+ if fi, err := os.Stat(name); err == nil && fi.IsDirectory() {
+ walkDir(name)
+ } else {
+ doFile(name, nil)
+ }
+ }
+ }
+ os.Exit(exitCode)
+}
+
+// doFile analyzes one file. If the reader is nil, the source code is read from the
+// named file.
+func doFile(name string, reader io.Reader) {
+ fs := token.NewFileSet()
+ parsedFile, err := parser.ParseFile(fs, name, reader, 0)
+ if err != nil {
+ error("%s: %s", name, err)
+ return
+ }
+ file := &File{fs.File(parsedFile.Pos())}
+ file.checkFile(name, parsedFile)
+}
+
+// Visitor for path.Walk - trivial. Just calls doFile on each file.
+// TODO: if govet becomes richer, might want to process
+// a directory (package) at a time.
+type V struct{}
+
+func (v V) VisitDir(path string, f *os.FileInfo) bool {
+ return true
+}
+
+func (v V) VisitFile(path string, f *os.FileInfo) {
+ if strings.HasSuffix(path, ".go") {
+ doFile(path, nil)
+ }
+}
+
+// walkDir recursively walks the tree looking for .go files.
+func walkDir(root string) {
+ errors := make(chan os.Error)
+ done := make(chan bool)
+ go func() {
+ for e := range errors {
+ error("walk error: %s", e)
+ }
+ done <- true
+ }()
+ path.Walk(root, V{}, errors)
+ close(errors)
+ <-done
+}
+
+// error formats the error to standard error, adding program
+// identification and a newline
+func error(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, "govet: "+format+"\n", args...)
+ setExit(2)
+}
+
+// Println is fmt.Println guarded by -v.
+func Println(args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Println(args...)
+}
+
+// Printf is fmt.Printf guarded by -v.
+func Printf(format string, args ...interface{}) {
+ if !*verbose {
+ return
+ }
+ fmt.Printf(format+"\n", args...)
+}
+
+// Bad reports an error and sets the exit code..
+func (f *File) Bad(pos token.Pos, args ...interface{}) {
+ f.Warn(pos, args...)
+ setExit(1)
+}
+
+// Badf reports a formatted error and sets the exit code.
+func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
+ f.Warnf(pos, format, args...)
+ setExit(1)
+}
+
+// Warn reports an error but does not set the exit code.
+func (f *File) Warn(pos token.Pos, args ...interface{}) {
+ loc := f.file.Position(pos).String() + ": "
+ fmt.Fprint(os.Stderr, loc+fmt.Sprintln(args...))
+}
+
+// Warnf reports a formatted error but does not set the exit code.
+func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
+ loc := f.file.Position(pos).String() + ": "
+ fmt.Fprintf(os.Stderr, loc+format+"\n", args...)
+}
+
+// checkFile checks all the top-level declarations in a file.
+func (f *File) checkFile(name string, file *ast.File) {
+ Println("Checking file", name)
+ ast.Walk(f, file)
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+ // TODO: could return nil for nodes that cannot contain a CallExpr -
+ // will shortcut traversal. Worthwhile?
+ switch n := node.(type) {
+ case *ast.CallExpr:
+ f.checkCallExpr(n)
+ }
+ return f
+}
+
+
+// checkCallExpr checks a call expression.
+func (f *File) checkCallExpr(call *ast.CallExpr) {
+ switch x := call.Fun.(type) {
+ case *ast.Ident:
+ f.checkCall(call, x.Name)
+ case *ast.SelectorExpr:
+ f.checkCall(call, x.Sel.Name)
+ }
+}
+
+// printfList records the formatted-print functions. The value is the location
+// of the format parameter.
+var printfList = map[string]int{
+ "Errorf": 0,
+ "Fatalf": 0,
+ "Fprintf": 1,
+ "Printf": 0,
+ "Sprintf": 0,
+}
+
+// printList records the unformatted-print functions. The value is the location
+// of the first parameter to be printed.
+var printList = map[string]int{
+ "Error": 0,
+ "Fatal": 0,
+ "Fprint": 1, "Fprintln": 1,
+ "Print": 0, "Println": 0,
+ "Sprint": 0, "Sprintln": 0,
+}
+
+// checkCall triggers the print-specific checks if the call invokes a print function.
+func (f *File) checkCall(call *ast.CallExpr, name string) {
+ if skip, ok := printfList[name]; ok {
+ f.checkPrintf(call, name, skip)
+ return
+ }
+ if skip, ok := printList[name]; ok {
+ f.checkPrint(call, name, skip)
+ return
+ }
+}
+
+// checkPrintf checks a call to a formatted print routine such as Printf.
+// The skip argument records how many arguments to ignore; that is,
+// call.Args[skip] is (well, should be) the format argument.
+func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
+ if len(call.Args) <= skip {
+ return
+ }
+ // Common case: literal is first argument.
+ arg := call.Args[skip]
+ lit, ok := arg.(*ast.BasicLit)
+ if !ok {
+ // Too hard to check.
+ if *verbose {
+ f.Warn(call.Pos(), "can't check args for call to", name)
+ }
+ return
+ }
+ if lit.Kind == token.STRING {
+ if bytes.IndexByte(lit.Value, '%') < 0 {
+ if len(call.Args) > skip+1 {
+ f.Badf(call.Pos(), "no formatting directive in %s call", name)
+ }
+ return
+ }
+ }
+ // Hard part: check formats against args.
+ // Trivial but useful test: count.
+ numPercent := 0
+ for i := 0; i < len(lit.Value); i++ {
+ if lit.Value[i] == '%' {
+ if i+1 < len(lit.Value) && lit.Value[i+1] == '%' {
+ // %% doesn't count.
+ i++
+ } else {
+ numPercent++
+ }
+ }
+ }
+ expect := len(call.Args) - (skip + 1)
+ if numPercent != expect {
+ f.Badf(call.Pos(), "wrong number of formatting directives in %s call: %d percent(s) for %d args", name, numPercent, expect)
+ }
+}
+
+var terminalNewline = []byte(`\n"`) // \n at end of interpreted string
+
+// checkPrint checks a call to an unformatted print routine such as Println.
+// The skip argument records how many arguments to ignore; that is,
+// call.Args[skip] is the first argument to be printed.
+func (f *File) checkPrint(call *ast.CallExpr, name string, skip int) {
+ isLn := strings.HasSuffix(name, "ln")
+ args := call.Args
+ if len(args) <= skip {
+ if *verbose && !isLn {
+ f.Badf(call.Pos(), "no args in %s call", name)
+ }
+ return
+ }
+ arg := args[skip]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if bytes.IndexByte(lit.Value, '%') >= 0 {
+ f.Badf(call.Pos(), "possible formatting directive in %s call", name)
+ }
+ }
+ if isLn {
+ // The last item, if a string, should not have a newline.
+ arg = args[len(call.Args)-1]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if bytes.HasSuffix(lit.Value, terminalNewline) {
+ f.Badf(call.Pos(), "%s call ends with newline", name)
+ }
+ }
+ }
+}
+
+// This function never executes, but it serves as a simple test for the program.
+// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go
+func BadFunctionUsedInTests() {
+ fmt.Println() // niladic call
+ fmt.Println("%s", "hi") // % in call to Println
+ fmt.Printf("%s", "hi", 3) // wrong # percents
+ fmt.Printf("%s%%%d", "hi", 3) // right # percents
+ Printf("now is the time", "buddy") // no %s
+ f := new(File)
+ f.Warn(0, "%s", "hello", 3) // % in call to added function
+ f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function
+}
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
index 77ac918bc..54b8f3360 100644
--- a/src/cmd/goyacc/Makefile
+++ b/src/cmd/goyacc/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=goyacc
GOFILES=\
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
index a5da5f0a1..c9fa6bfb9 100644
--- a/src/cmd/goyacc/goyacc.go
+++ b/src/cmd/goyacc/goyacc.go
@@ -299,17 +299,17 @@ type Resrv struct {
}
var resrv = []Resrv{
- Resrv{"binary", BINARY},
- Resrv{"left", LEFT},
- Resrv{"nonassoc", BINARY},
- Resrv{"prec", PREC},
- Resrv{"right", RIGHT},
- Resrv{"start", START},
- Resrv{"term", TERM},
- Resrv{"token", TERM},
- Resrv{"type", TYPEDEF},
- Resrv{"union", UNION},
- Resrv{"struct", UNION},
+ {"binary", BINARY},
+ {"left", LEFT},
+ {"nonassoc", BINARY},
+ {"prec", PREC},
+ {"right", RIGHT},
+ {"start", START},
+ {"term", TERM},
+ {"token", TERM},
+ {"type", TYPEDEF},
+ {"union", UNION},
+ {"struct", UNION},
}
var zznewstate = 0
@@ -1032,7 +1032,7 @@ func chfind(t int, s string) int {
func cpyunion() {
if !lflag {
- fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
}
fmt.Fprintf(ftable, "type\tyySymType\tstruct")
@@ -1075,7 +1075,7 @@ func cpycode() {
lineno++
}
if !lflag {
- fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
}
for c != EOF {
if c == '%' {
@@ -1158,7 +1158,7 @@ func dumpprod(curprod []int, max int) {
func cpyact(curprod []int, max int) {
if !lflag {
- fmt.Fprintf(fcode, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(fcode, "\n//line %v:%v\n", infile, lineno)
}
lno := lineno
@@ -2066,6 +2066,7 @@ nextk:
func output() {
var c, u, v int
+ fmt.Fprintf(ftable, "\n//line yacctab:1\n")
fmt.Fprintf(ftable, "var\tyyExca = []int {\n")
noset := mkset()
@@ -2825,8 +2826,10 @@ func others() {
c = getrune(finput)
}
- parts := strings.Split(yaccpar, "yyrun()", 2)
// copy yaccpar
+ fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
+
+ parts := strings.Split(yaccpar, "yyrun()", 2)
fmt.Fprintf(ftable, "%v", parts[0])
ftable.Write(fcode.Bytes())
fmt.Fprintf(ftable, "%v", parts[1])
@@ -3035,7 +3038,7 @@ func open(s string) *bufio.Reader {
return bufio.NewReader(fi)
}
-func create(s string, m int) *bufio.Writer {
+func create(s string, m uint32) *bufio.Writer {
fo, err := os.Open(s, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, m)
if err != nil {
error("error opening %v: %v", s, err)
@@ -3049,7 +3052,7 @@ func create(s string, m int) *bufio.Writer {
//
func error(s string, v ...interface{}) {
nerrors++
- fmt.Fprintf(stderr, s, v)
+ fmt.Fprintf(stderr, s, v...)
fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
if fatfl != 0 {
summary()
@@ -3136,7 +3139,7 @@ out:
c = yyTok2[1] /* unknown char */
}
if yyDebug >= 3 {
- fmt.Printf("lex %.4x %s\n", uint(yychar), yyTokname(c))
+ fmt.Printf("lex %U %s\n", uint(yychar), yyTokname(c))
}
return c
}
@@ -3241,7 +3244,7 @@ yydefault:
Errflag = 3
/* find a state where "error" is a legal shift action */
- for yyp >= len(YYS) {
+ for yyp >= 0 {
yyn = yyPact[YYS[yyp].yys] + yyErrCode
if yyn >= 0 && yyn < yyLast {
yystate = yyAct[yyn] /* simulate a shift of "error" */
diff --git a/src/cmd/goyacc/units.y b/src/cmd/goyacc/units.y
index bd5517e8b..a7d472fc6 100644
--- a/src/cmd/goyacc/units.y
+++ b/src/cmd/goyacc/units.y
@@ -215,7 +215,7 @@ expr0:
type UnitsLex int
-func (_ UnitsLex) Lex(yylval *yySymType) int {
+func (UnitsLex) Lex(yylval *yySymType) int {
var c, i int
c = peekrune
@@ -280,7 +280,7 @@ numb:
return VAL
}
-func (_ UnitsLex) Error(s string) {
+func (UnitsLex) Error(s string) {
Error("syntax error, last name: %v", sym)
}
@@ -298,7 +298,7 @@ func main() {
f, err := os.Open(file, os.O_RDONLY, 0)
if err != nil {
- fmt.Printf("error opening %v: %v\n", file, err)
+ fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
os.Exit(1)
}
fi = bufio.NewReader(f)
@@ -390,7 +390,7 @@ func rdigit(c int) bool {
func Error(s string, v ...interface{}) {
fmt.Printf("%v: %v\n\t", lineno, line)
- fmt.Printf(s, v)
+ fmt.Printf(s, v...)
fmt.Printf("\n")
nerrors++
diff --git a/src/cmd/hgpatch/Makefile b/src/cmd/hgpatch/Makefile
index f7d64bc12..1ef98d7f9 100644
--- a/src/cmd/hgpatch/Makefile
+++ b/src/cmd/hgpatch/Makefile
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=hgpatch
GOFILES=\
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index f6ea36da8..bd4b563f9 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -153,7 +153,7 @@ func main() {
changed[o.Dst] = 1
}
if o.Mode != 0 {
- chk(os.Chmod(o.Dst, o.Mode&0755))
+ chk(os.Chmod(o.Dst, uint32(o.Mode&0755)))
undoRevert(o.Dst)
changed[o.Dst] = 1
}
@@ -192,7 +192,7 @@ func makeParent(name string) {
// Copy of os.MkdirAll but adds to undo log after
// creating a directory.
-func mkdirAll(path string, perm int) os.Error {
+func mkdirAll(path string, perm uint32) os.Error {
dir, err := os.Lstat(path)
if err == nil {
if dir.IsDirectory() {
@@ -318,11 +318,9 @@ func hgRename(dst, src string) os.Error {
return err
}
-func copy(a []string) []string {
+func dup(a []string) []string {
b := make([]string, len(a))
- for i, s := range a {
- b[i] = s
- }
+ copy(b, a)
return b
}
@@ -379,7 +377,7 @@ func run(argv []string, input []byte) (out string, err os.Error) {
return
Error:
- err = &runError{copy(argv), err}
+ err = &runError{dup(argv), err}
return
}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
new file mode 100644
index 000000000..210f10ab5
--- /dev/null
+++ b/src/cmd/ld/data.c
@@ -0,0 +1,914 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.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.
+
+// Data layout and relocation.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/pe.h"
+
+void dynreloc(void);
+
+/*
+ * divide-and-conquer list-link
+ * sort of Sym* structures.
+ * Used for the data block.
+ */
+int
+datcmp(Sym *s1, Sym *s2)
+{
+ if(s1->type != s2->type)
+ return (int)s1->type - (int)s2->type;
+ if(s1->size != s2->size) {
+ if(s1->size < s2->size)
+ return -1;
+ return +1;
+ }
+ return strcmp(s1->name, s2->name);
+}
+
+Sym*
+datsort(Sym *l)
+{
+ Sym *l1, *l2, *le;
+
+ if(l == 0 || l->next == 0)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->next;
+ if(l2 == 0)
+ break;
+ l2 = l2->next;
+ if(l2 == 0)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = 0;
+ l1 = datsort(l);
+ l2 = datsort(l2);
+
+ /* set up lead element */
+ if(datcmp(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->next;
+ } else {
+ l = l2;
+ l2 = l2->next;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == 0) {
+ while(l2) {
+ le->next = l2;
+ le = l2;
+ l2 = l2->next;
+ }
+ le->next = 0;
+ break;
+ }
+ if(l2 == 0) {
+ while(l1) {
+ le->next = l1;
+ le = l1;
+ l1 = l1->next;
+ }
+ break;
+ }
+ if(datcmp(l1, l2) < 0) {
+ le->next = l1;
+ le = l1;
+ l1 = l1->next;
+ } else {
+ le->next = l2;
+ le = l2;
+ l2 = l2->next;
+ }
+ }
+ le->next = 0;
+ return l;
+}
+
+Reloc*
+addrel(Sym *s)
+{
+ if(s->nr >= s->maxr) {
+ if(s->maxr == 0)
+ s->maxr = 4;
+ else
+ s->maxr <<= 1;
+ s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
+ if(s->r == 0) {
+ diag("out of memory");
+ errorexit();
+ }
+ memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
+ }
+ return &s->r[s->nr++];
+}
+
+void
+relocsym(Sym *s)
+{
+ Reloc *r;
+ Prog p;
+ int32 i, off, siz, fl;
+ vlong o;
+ uchar *cast;
+
+ cursym = s;
+ memset(&p, 0, sizeof p);
+ for(r=s->r; r<s->r+s->nr; r++) {
+ off = r->off;
+ siz = r->siz;
+ if(off < 0 || off+(siz&~Rbig) > s->np) {
+ diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np);
+ continue;
+ }
+ if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) {
+ diag("%s: not defined", r->sym->name);
+ continue;
+ }
+ if(r->type >= 256)
+ continue;
+
+ if(r->sym != S && r->sym->type == SDYNIMPORT)
+ diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
+
+ if(r->sym != S && !r->sym->reachable)
+ diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
+
+ switch(r->type) {
+ default:
+ o = 0;
+ if(archreloc(r, s, &o) < 0)
+ diag("unknown reloc %d", r->type);
+ break;
+ case D_ADDR:
+ o = symaddr(r->sym) + r->add;
+ break;
+ case D_PCREL:
+ o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz);
+ break;
+ case D_SIZE:
+ o = r->sym->size + r->add;
+ break;
+ }
+//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
+ switch(siz) {
+ default:
+ cursym = s;
+ diag("bad reloc size %#ux for %s", siz, r->sym->name);
+ case 4 + Rbig:
+ fl = o;
+ s->p[off] = fl>>24;
+ s->p[off+1] = fl>>16;
+ s->p[off+2] = fl>>8;
+ s->p[off+3] = fl;
+ break;
+ case 4 + Rlittle:
+ fl = o;
+ s->p[off] = fl;
+ s->p[off+1] = fl>>8;
+ s->p[off+2] = fl>>16;
+ s->p[off+3] = fl>>24;
+ break;
+ case 4:
+ fl = o;
+ cast = (uchar*)&fl;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ }
+}
+
+void
+reloc(void)
+{
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ Bflush(&bso);
+
+ for(s=textp; s!=S; s=s->next)
+ relocsym(s);
+ for(s=datap; s!=S; s=s->next)
+ relocsym(s);
+}
+
+void
+dynrelocsym(Sym *s)
+{
+ Reloc *r;
+
+ for(r=s->r; r<s->r+s->nr; r++)
+ if(r->sym->type == SDYNIMPORT || r->type >= 256)
+ adddynrel(s, r);
+}
+
+void
+dynreloc(void)
+{
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ Bflush(&bso);
+
+ for(s=textp; s!=S; s=s->next)
+ dynrelocsym(s);
+ for(s=datap; s!=S; s=s->next)
+ dynrelocsym(s);
+ if(iself)
+ elfdynhash();
+}
+
+void
+symgrow(Sym *s, int32 siz)
+{
+ if(s->np >= siz)
+ return;
+
+ if(s->maxp < siz) {
+ if(s->maxp == 0)
+ s->maxp = 8;
+ while(s->maxp < siz)
+ s->maxp <<= 1;
+ s->p = realloc(s->p, s->maxp);
+ if(s->p == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ memset(s->p+s->np, 0, s->maxp-s->np);
+ }
+ s->np = siz;
+}
+
+void
+savedata(Sym *s, Prog *p)
+{
+ int32 off, siz, i, fl;
+ uchar *cast;
+ vlong o;
+ Reloc *r;
+
+ off = p->from.offset;
+ siz = p->datasize;
+ symgrow(s, off+siz);
+
+ switch(p->to.type) {
+ default:
+ diag("bad data: %P", p);
+ break;
+
+ case D_FCONST:
+ switch(siz) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (uchar*)&fl;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[fnuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&p->to.ieee;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[fnuxi8[i]];
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(i=0; i<siz; i++)
+ s->p[off+i] = p->to.scon[i];
+ break;
+
+ case D_CONST:
+ if(p->to.sym)
+ goto Addr;
+ o = p->to.offset;
+ fl = o;
+ cast = (uchar*)&fl;
+ switch(siz) {
+ default:
+ diag("bad nuxi %d\n%P", siz, p);
+ break;
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ break;
+
+ case D_ADDR:
+ case D_SIZE:
+ Addr:
+ r = addrel(s);
+ r->off = off;
+ r->siz = siz;
+ r->sym = p->to.sym;
+ r->type = p->to.type;
+ if(r->type != D_SIZE)
+ r->type = D_ADDR;
+ r->add = p->to.offset;
+ break;
+ }
+}
+
+static void
+blk(Sym *allsym, int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr;
+ uchar *p, *ep;
+
+ for(sym = allsym; sym != nil; sym = sym->next)
+ if(!(sym->type&SSUB) && sym->value >= addr)
+ break;
+
+ eaddr = addr+size;
+ for(; sym != nil; sym = sym->next) {
+ if(sym->type&SSUB)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+ if(sym->value < addr) {
+ diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
+ errorexit();
+ }
+ cursym = sym;
+ for(; addr < sym->value; addr++)
+ cput(0);
+ p = sym->p;
+ ep = p + sym->np;
+ while(p < ep)
+ cput(*p++);
+ addr += sym->np;
+ for(; addr < sym->value+sym->size; addr++)
+ cput(0);
+ if(addr != sym->value+sym->size) {
+ diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
+ errorexit();
+ }
+ }
+
+ for(; addr < eaddr; addr++)
+ cput(0);
+ cflush();
+}
+
+void
+codeblk(int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr, n, epc;
+ Prog *p;
+ uchar *q;
+
+ if(debug['a'])
+ Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+
+ blk(textp, addr, size);
+
+ /* again for printing */
+ if(!debug['a'])
+ return;
+
+ for(sym = textp; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= addr)
+ break;
+ }
+
+ eaddr = addr + size;
+ for(; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+
+ if(addr < sym->value) {
+ Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+ for(; addr < sym->value; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ Bprint(&bso, "\n");
+ }
+ p = sym->text;
+ if(p == nil) {
+ Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
+ n = sym->size;
+ q = sym->p;
+
+ while(n >= 16) {
+ Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
+ addr += 16;
+ q += 16;
+ n -= 16;
+ }
+ if(n > 0)
+ Bprint(&bso, "%.6ux\t%-20.*I\n", addr, n, q);
+ addr += n;
+ continue;
+ }
+
+ Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
+ for(p = p->link; p != P; p = p->link) {
+ if(p->link != P)
+ epc = p->link->pc;
+ else
+ epc = sym->value + sym->size;
+ Bprint(&bso, "%.6ux\t", p->pc);
+ q = sym->p + p->pc - sym->value;
+ n = epc - p->pc;
+ Bprint(&bso, "%-20.*I | %P\n", n, q, p);
+ addr += n;
+ }
+ }
+
+ if(addr < eaddr) {
+ Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+ for(; addr < eaddr; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ }
+ Bflush(&bso);
+}
+
+void
+datblk(int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr;
+ uchar *p, *ep;
+
+ if(debug['a'])
+ Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+
+ blk(datap, addr, size);
+
+ /* again for printing */
+ if(!debug['a'])
+ return;
+
+ for(sym = datap; sym != nil; sym = sym->next)
+ if(sym->value >= addr)
+ break;
+
+ eaddr = addr + size;
+ for(; sym != nil; sym = sym->next) {
+ if(sym->value >= eaddr)
+ break;
+ if(addr < sym->value) {
+ Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
+ addr = sym->value;
+ }
+ Bprint(&bso, "%-20s %.8ux|", sym->name, addr);
+ p = sym->p;
+ ep = p + sym->np;
+ while(p < ep)
+ Bprint(&bso, " %.2ux", *p++);
+ addr += sym->np;
+ for(; addr < sym->value+sym->size; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ Bprint(&bso, "\n");
+ }
+
+ if(addr < eaddr)
+ Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", addr);
+ Bprint(&bso, "%-20s %.8ux|\n", "", eaddr);
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s && n > 0; s++) {
+ cput(*s);
+ n--;
+ }
+ while(n > 0) {
+ cput(0);
+ n--;
+ }
+}
+
+vlong
+addstring(Sym *s, char *str)
+{
+ int n;
+ int32 r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ r = s->size;
+ n = strlen(str)+1;
+ if(strcmp(s->name, ".shstrtab") == 0)
+ elfsetstring(str, r);
+ symgrow(s, r+n);
+ memmove(s->p+r, str, n);
+ s->size += n;
+ return r;
+}
+
+vlong
+adduintxx(Sym *s, uint64 v, int wid)
+{
+ int32 i, r, fl;
+ vlong o;
+ uchar *cast;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ r = s->size;
+ s->size += wid;
+ symgrow(s, s->size);
+ assert(r+wid <= s->size);
+ fl = v;
+ cast = (uchar*)&fl;
+ switch(wid) {
+ case 1:
+ s->p[r] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[r+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[r+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ o = v;
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[r+i] = cast[inuxi8[i]];
+ break;
+ }
+ return r;
+}
+
+vlong
+adduint8(Sym *s, uint8 v)
+{
+ return adduintxx(s, v, 1);
+}
+
+vlong
+adduint16(Sym *s, uint16 v)
+{
+ return adduintxx(s, v, 2);
+}
+
+vlong
+adduint32(Sym *s, uint32 v)
+{
+ return adduintxx(s, v, 4);
+}
+
+vlong
+adduint64(Sym *s, uint64 v)
+{
+ return adduintxx(s, v, 8);
+}
+
+vlong
+addaddrplus(Sym *s, Sym *t, int32 add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += PtrSize;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = PtrSize;
+ r->type = D_ADDR;
+ r->add = add;
+ return i;
+}
+
+vlong
+addpcrelplus(Sym *s, Sym *t, int32 add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->add = add;
+ r->type = D_PCREL;
+ r->siz = 4;
+ return i;
+}
+
+vlong
+addaddr(Sym *s, Sym *t)
+{
+ return addaddrplus(s, t, 0);
+}
+
+vlong
+addsize(Sym *s, Sym *t)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += PtrSize;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = PtrSize;
+ r->type = D_SIZE;
+ return i;
+}
+
+void
+dodata(void)
+{
+ int32 h, t, datsize;
+ Section *sect;
+ Sym *s, *last, **l;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+
+ last = nil;
+ datap = nil;
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash){
+ if(!s->reachable || s->special)
+ continue;
+ if(STEXT < s->type && s->type < SXREF) {
+ if(last == nil)
+ datap = s;
+ else
+ last->next = s;
+ s->next = nil;
+ last = s;
+ }
+ }
+ }
+
+ for(s = datap; s != nil; s = s->next) {
+ if(s->np > 0 && s->type == SBSS) // TODO: necessary?
+ s->type = SDATA;
+ if(s->np > s->size)
+ diag("%s: initialize bounds (%lld < %d)",
+ s->name, (vlong)s->size, s->np);
+ }
+
+ /*
+ * now that we have the datap list, but before we start
+ * to assign addresses, record all the necessary
+ * dynamic relocations. these will grow the relocation
+ * symbol, which is itself data.
+ */
+ dynreloc();
+
+ /* some symbols may no longer belong in datap (Mach-O) */
+ for(l=&datap; (s=*l) != nil; ) {
+ if(s->type <= STEXT || SXREF <= s->type)
+ *l = s->next;
+ else
+ l = &s->next;
+ }
+ *l = nil;
+
+ datap = datsort(datap);
+
+ /*
+ * allocate data sections. list is sorted by type,
+ * so we can just walk it for each piece we want to emit.
+ */
+
+ /* read-only data */
+ sect = addsection(&segtext, ".rodata", 06);
+ sect->vaddr = 0;
+ datsize = 0;
+ s = datap;
+ for(; s != nil && s->type < SDATA; s = s->next) {
+ s->type = SRODATA;
+ t = rnd(s->size, 4);
+ s->size = t;
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+
+ /* data */
+ datsize = 0;
+ sect = addsection(&segdata, ".data", 06);
+ sect->vaddr = 0;
+ for(; s != nil && s->type < SBSS; s = s->next) {
+ s->type = SDATA;
+ t = s->size;
+ if(t == 0 && s->name[0] != '.') {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ if(t & 1)
+ ;
+ else if(t & 2)
+ datsize = rnd(datsize, 2);
+ else if(t & 4)
+ datsize = rnd(datsize, 4);
+ else
+ datsize = rnd(datsize, 8);
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+
+ /* bss */
+ sect = addsection(&segdata, ".bss", 06);
+ sect->vaddr = datsize;
+ for(; s != nil; s = s->next) {
+ if(s->type != SBSS) {
+ cursym = s;
+ diag("unexpected symbol type %d", s->type);
+ }
+ t = s->size;
+ if(t & 1)
+ ;
+ else if(t & 2)
+ datsize = rnd(datsize, 2);
+ else if(t & 4)
+ datsize = rnd(datsize, 4);
+ else
+ datsize = rnd(datsize, 8);
+ s->size = t;
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+}
+
+// assign addresses to text
+void
+textaddress(void)
+{
+ uvlong va;
+ Prog *p;
+ Section *sect;
+ Sym *sym, *sub;
+
+ addsection(&segtext, ".text", 05);
+
+ // Assign PCs in text segment.
+ // Could parallelize, by assigning to text
+ // and then letting threads copy down, but probably not worth it.
+ sect = segtext.sect;
+ va = INITTEXT;
+ sect->vaddr = va;
+ for(sym = textp; sym != nil; sym = sym->next) {
+ if(sym->type & SSUB)
+ continue;
+ sym->value = 0;
+ for(sub = sym; sub != S; sub = sub->sub) {
+ sub->value += va;
+ for(p = sub->text; p != P; p = p->link)
+ p->pc += sub->value;
+ }
+ if(sym->size == 0 && sym->sub != S) {
+ cursym = sym;
+ }
+ va += sym->size;
+ }
+ sect->len = va - sect->vaddr;
+}
+
+// assign addresses
+void
+address(void)
+{
+ Section *s, *text, *data, *rodata, *bss;
+ Sym *sym, *sub;
+ uvlong va;
+
+ va = INITTEXT;
+ segtext.rwx = 05;
+ segtext.vaddr = va;
+ segtext.fileoff = HEADR;
+ for(s=segtext.sect; s != nil; s=s->next) {
+ s->vaddr = va;
+ va += s->len;
+ segtext.len = va - INITTEXT;
+ va = rnd(va, INITRND);
+ }
+ segtext.filelen = segtext.len;
+
+ segdata.rwx = 06;
+ segdata.vaddr = va;
+ segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
+ if(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);
+ segdata.fileoff = segtext.fileoff + segtext.filelen;
+ }
+ for(s=segdata.sect; s != nil; s=s->next) {
+ s->vaddr = va;
+ va += s->len;
+ segdata.len = va - segdata.vaddr;
+ }
+ segdata.filelen = segdata.sect->len; // assume .data is first
+
+ text = segtext.sect;
+ rodata = segtext.sect->next;
+ data = segdata.sect;
+ bss = segdata.sect->next;
+
+ for(sym = datap; sym != nil; sym = sym->next) {
+ cursym = sym;
+ if(sym->type < SDATA)
+ sym->value += rodata->vaddr;
+ else
+ sym->value += data->vaddr;
+ for(sub = sym->sub; sub != nil; sub = sub->sub)
+ sub->value += sym->value;
+ }
+
+ xdefine("text", STEXT, text->vaddr);
+ xdefine("etext", STEXT, text->vaddr + text->len);
+ xdefine("rodata", SRODATA, rodata->vaddr);
+ xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
+ xdefine("data", SBSS, data->vaddr);
+ xdefine("edata", SBSS, data->vaddr + data->len);
+ xdefine("end", SBSS, segdata.vaddr + segdata.len);
+
+ sym = lookup("pclntab", 0);
+ xdefine("epclntab", SRODATA, sym->value + sym->size);
+ sym = lookup("symtab", 0);
+ xdefine("esymtab", SRODATA, sym->value + sym->size);
+}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
new file mode 100644
index 000000000..506c6e5db
--- /dev/null
+++ b/src/cmd/ld/dwarf.c
@@ -0,0 +1,2547 @@
+// 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.
+
+// TODO/NICETOHAVE:
+// - eliminate DW_CLS_ if not used
+// - package info in compilation units
+// - assign global variables and types to their packages
+// - (upstream) type info for C parts of runtime
+// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+// ptype struct '[]uint8' and qualifiers need to be quoted away
+// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
+// - file:line info for variables
+// - make strings a typedef so prettyprinters can see the underlying string type
+//
+#include "l.h"
+#include "lib.h"
+#include "../ld/dwarf.h"
+#include "../ld/dwarf_defs.h"
+#include "../ld/elf.h"
+#include "../ld/macho.h"
+
+/*
+ * Offsets and sizes of the debug_* sections in the cout file.
+ */
+
+static vlong abbrevo;
+static vlong abbrevsize;
+static vlong lineo;
+static vlong linesize;
+static vlong infoo; // also the base for DWDie->offs and reference attributes.
+static vlong infosize;
+static vlong frameo;
+static vlong framesize;
+static vlong pubnameso;
+static vlong pubnamessize;
+static vlong pubtypeso;
+static vlong pubtypessize;
+static vlong arangeso;
+static vlong arangessize;
+static vlong gdbscripto;
+static vlong gdbscriptsize;
+
+static char gdbscript[1024];
+
+/*
+ * Basic I/O
+ */
+
+static void
+addrput(vlong addr)
+{
+ switch(PtrSize) {
+ case 4:
+ LPUT(addr);
+ break;
+ case 8:
+ VPUT(addr);
+ break;
+ }
+}
+
+static int
+uleb128enc(uvlong v, char* dst)
+{
+ uint8 c, len;
+
+ len = 0;
+ do {
+ c = v & 0x7f;
+ v >>= 7;
+ if (v)
+ c |= 0x80;
+ if (dst)
+ *dst++ = c;
+ len++;
+ } while (c & 0x80);
+ return len;
+};
+
+static int
+sleb128enc(vlong v, char *dst)
+{
+ uint8 c, s, len;
+
+ len = 0;
+ do {
+ c = v & 0x7f;
+ s = v & 0x40;
+ v >>= 7;
+ if ((v != -1 || !s) && (v != 0 || s))
+ c |= 0x80;
+ if (dst)
+ *dst++ = c;
+ len++;
+ } while(c & 0x80);
+ return len;
+}
+
+static void
+uleb128put(vlong v)
+{
+ char buf[10];
+ strnput(buf, uleb128enc(v, buf));
+}
+
+static void
+sleb128put(vlong v)
+{
+ char buf[10];
+ strnput(buf, sleb128enc(v, buf));
+}
+
+/*
+ * Defining Abbrevs. This is hardcoded, and there will be
+ * only a handful of them. The DWARF spec places no restriction on
+ * the ordering of atributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ * This implementation relies on tag, attr < 127, so they serialize as
+ * a char. Higher numbered user-defined tags or attributes can be used
+ * for storing internal data but won't be serialized.
+ */
+typedef struct DWAttrForm DWAttrForm;
+struct DWAttrForm {
+ uint8 attr;
+ uint8 form;
+};
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+enum
+{
+ DW_ABRV_NULL,
+ DW_ABRV_COMPUNIT,
+ DW_ABRV_FUNCTION,
+ DW_ABRV_VARIABLE,
+ DW_ABRV_AUTO,
+ DW_ABRV_PARAM,
+ DW_ABRV_STRUCTFIELD,
+ DW_ABRV_FUNCTYPEPARAM,
+ DW_ABRV_DOTDOTDOT,
+ DW_ABRV_ARRAYRANGE,
+ DW_ABRV_NULLTYPE,
+ DW_ABRV_BASETYPE,
+ DW_ABRV_ARRAYTYPE,
+ DW_ABRV_CHANTYPE,
+ DW_ABRV_FUNCTYPE,
+ DW_ABRV_IFACETYPE,
+ DW_ABRV_MAPTYPE,
+ DW_ABRV_PTRTYPE,
+ DW_ABRV_SLICETYPE,
+ DW_ABRV_STRINGTYPE,
+ DW_ABRV_STRUCTTYPE,
+ DW_ABRV_TYPEDECL,
+ DW_NABRV
+};
+
+typedef struct DWAbbrev DWAbbrev;
+static struct DWAbbrev {
+ uint8 tag;
+ uint8 children;
+ DWAttrForm attr[30];
+} abbrevs[DW_NABRV] = {
+ /* The mandatory DW_ABRV_NULL entry. */
+ { 0 },
+ /* COMPUNIT */
+ {
+ DW_TAG_compile_unit, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_language, DW_FORM_data1,
+ DW_AT_low_pc, DW_FORM_addr,
+ DW_AT_high_pc, DW_FORM_addr,
+ DW_AT_stmt_list, DW_FORM_data4,
+ 0, 0
+ },
+ /* FUNCTION */
+ {
+ DW_TAG_subprogram, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_low_pc, DW_FORM_addr,
+ DW_AT_high_pc, DW_FORM_addr,
+ DW_AT_external, DW_FORM_flag,
+ 0, 0
+ },
+ /* VARIABLE */
+ {
+ DW_TAG_variable, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_external, DW_FORM_flag,
+ 0, 0
+ },
+ /* AUTO */
+ {
+ DW_TAG_variable, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* PARAM */
+ {
+ DW_TAG_formal_parameter, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* STRUCTFIELD */
+ {
+ DW_TAG_member, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_data_member_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* FUNCTYPEPARAM */
+ {
+ DW_TAG_formal_parameter, DW_CHILDREN_no,
+ // No name!
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* DOTDOTDOT */
+ {
+ DW_TAG_unspecified_parameters, DW_CHILDREN_no,
+ 0, 0
+ },
+ /* ARRAYRANGE */
+ {
+ DW_TAG_subrange_type, DW_CHILDREN_no,
+ // No name!
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_upper_bound, DW_FORM_data1,
+ 0, 0
+ },
+
+ // Below here are the types considered public by ispubtype
+ /* NULLTYPE */
+ {
+ DW_TAG_unspecified_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+ /* BASETYPE */
+ {
+ DW_TAG_base_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_encoding, DW_FORM_data1,
+ DW_AT_byte_size, DW_FORM_data1,
+ 0, 0
+ },
+ /* ARRAYTYPE */
+ // child is subrange with upper bound
+ {
+ DW_TAG_array_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* CHANTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* FUNCTYPE */
+ {
+ DW_TAG_subroutine_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+// DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* IFACETYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* MAPTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* PTRTYPE */
+ {
+ DW_TAG_pointer_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* SLICETYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRINGTYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRUCTTYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* TYPEDECL */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+};
+
+static void
+writeabbrev(void)
+{
+ int i, n;
+
+ abbrevo = cpos();
+ for (i = 1; i < DW_NABRV; i++) {
+ // See section 7.5.3
+ uleb128put(i);
+ uleb128put(abbrevs[i].tag);
+ cput(abbrevs[i].children);
+ // 0 is not a valid attr or form, and DWAbbrev.attr is
+ // 0-terminated, so we can treat it as a string
+ n = strlen((char*)abbrevs[i].attr) / 2;
+ strnput((char*)abbrevs[i].attr,
+ (n+1) * sizeof(DWAttrForm));
+ }
+ cput(0);
+ abbrevsize = cpos() - abbrevo;
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+
+enum
+{
+ HASHSIZE = 107
+};
+
+static uint32
+hashstr(char* s)
+{
+ uint32 h;
+
+ h = 0;
+ while (*s)
+ h = h+h+h + *s++;
+ return h % HASHSIZE;
+}
+
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+
+typedef struct DWAttr DWAttr;
+struct DWAttr {
+ DWAttr *link;
+ uint8 atr; // DW_AT_
+ uint8 cls; // DW_CLS_
+ vlong value;
+ char *data;
+};
+
+typedef struct DWDie DWDie;
+struct DWDie {
+ int abbrev;
+ DWDie *link;
+ DWDie *child;
+ DWAttr *attr;
+ // offset into .debug_info section, i.e relative to
+ // infoo. only valid after call to putdie()
+ vlong offs;
+ DWDie **hash; // optional index of children by name, enabled by mkindex()
+ DWDie *hlink; // bucket chain in parent's index
+};
+
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
+
+static DWDie dwroot;
+static DWDie dwtypes;
+static DWDie dwglobals;
+
+static DWAttr*
+newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
+{
+ DWAttr *a;
+
+ a = mal(sizeof *a);
+ a->link = die->attr;
+ die->attr = a;
+ a->atr = attr;
+ a->cls = cls;
+ a->value = value;
+ a->data = data;
+ return a;
+}
+
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+static DWAttr*
+getattr(DWDie *die, uint8 attr)
+{
+ DWAttr *a, *b;
+
+ if (die->attr->atr == attr)
+ return die->attr;
+
+ a = die->attr;
+ b = a->link;
+ while (b != nil) {
+ if (b->atr == attr) {
+ a->link = b->link;
+ b->link = die->attr;
+ die->attr = b;
+ return b;
+ }
+ a = b;
+ b = b->link;
+ }
+ 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.
+static DWDie*
+newdie(DWDie *parent, int abbrev, char *name)
+{
+ DWDie *die;
+ int h;
+
+ die = mal(sizeof *die);
+ die->abbrev = abbrev;
+ die->link = parent->child;
+ parent->child = die;
+
+ newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
+
+ if (parent->hash) {
+ h = hashstr(name);
+ die->hlink = parent->hash[h];
+ parent->hash[h] = die;
+ }
+
+ return die;
+}
+
+static void
+mkindex(DWDie *die)
+{
+ die->hash = mal(HASHSIZE * sizeof(DWDie*));
+}
+
+// Find child by AT_name using hashtable if available or linear scan
+// if not.
+static DWDie*
+find(DWDie *die, char* name)
+{
+ DWDie *a, *b;
+ int h;
+
+ if (die->hash == nil) {
+ for (a = die->child; a != nil; a = a->link)
+ if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+ return a;
+ return nil;
+ }
+
+ h = hashstr(name);
+ a = die->hash[h];
+
+ if (a == nil)
+ return nil;
+
+
+ if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+ return a;
+
+ // Move found ones to head of the list.
+ b = a->hlink;
+ while (b != nil) {
+ if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
+ a->hlink = b->hlink;
+ b->hlink = die->hash[h];
+ die->hash[h] = b;
+ return b;
+ }
+ a = b;
+ b = b->hlink;
+ }
+ return nil;
+}
+
+static DWDie*
+find_or_diag(DWDie *die, char* name)
+{
+ DWDie *r;
+ r = find(die, name);
+ if (r == nil)
+ diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
+ return r;
+}
+
+static DWAttr*
+newrefattr(DWDie *die, uint8 attr, DWDie* ref)
+{
+ if (ref == nil)
+ return nil;
+ return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
+}
+
+static int fwdcount;
+
+static void
+putattr(int form, int cls, vlong value, char *data)
+{
+ switch(form) {
+ case DW_FORM_addr: // address
+ addrput(value);
+ break;
+
+ case DW_FORM_block1: // block
+ value &= 0xff;
+ cput(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block2: // block
+ value &= 0xffff;
+ WPUT(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block4: // block
+ value &= 0xffffffff;
+ LPUT(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block: // block
+ uleb128put(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_data1: // constant
+ cput(value);
+ break;
+
+ case DW_FORM_data2: // constant
+ WPUT(value);
+ break;
+
+ case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
+ LPUT(value);
+ break;
+
+ case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
+ VPUT(value);
+ break;
+
+ case DW_FORM_sdata: // constant
+ sleb128put(value);
+ break;
+
+ case DW_FORM_udata: // constant
+ uleb128put(value);
+ break;
+
+ case DW_FORM_string: // string
+ strnput(data, value+1);
+ break;
+
+ case DW_FORM_flag: // flag
+ cput(value?1:0);
+ break;
+
+ case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ if (data == nil) {
+ diag("null dwarf reference");
+ LPUT(0); // invalid dwarf, gdb will complain.
+ } else {
+ if (((DWDie*)data)->offs == 0)
+ fwdcount++;
+ LPUT(((DWDie*)data)->offs);
+ }
+ break;
+
+ case DW_FORM_ref1: // reference within the compilation unit
+ case DW_FORM_ref2: // reference
+ case DW_FORM_ref4: // reference
+ case DW_FORM_ref8: // reference
+ case DW_FORM_ref_udata: // reference
+
+ case DW_FORM_strp: // string
+ case DW_FORM_indirect: // (see Section 7.5.3)
+ default:
+ diag("Unsupported atribute form %d / class %d", form, cls);
+ errorexit();
+ }
+}
+
+// Note that we can (and do) add arbitrary attributes to a DIE, but
+// only the ones actually listed in the Abbrev will be written out.
+static void
+putattrs(int abbrev, DWAttr* attr)
+{
+ DWAttr *attrs[DW_AT_recursive + 1];
+ DWAttrForm* af;
+
+ memset(attrs, 0, sizeof attrs);
+ for( ; attr; attr = attr->link)
+ if (attr->atr < nelem(attrs))
+ attrs[attr->atr] = attr;
+
+ for(af = abbrevs[abbrev].attr; af->attr; af++)
+ if (attrs[af->attr])
+ putattr(af->form,
+ attrs[af->attr]->cls,
+ attrs[af->attr]->value,
+ attrs[af->attr]->data);
+ else
+ putattr(af->form, 0, 0, 0);
+}
+
+static void putdie(DWDie* die);
+
+static void
+putdies(DWDie* die)
+{
+ for(; die; die = die->link)
+ putdie(die);
+}
+
+static void
+putdie(DWDie* die)
+{
+ die->offs = cpos() - infoo;
+ uleb128put(die->abbrev);
+ putattrs(die->abbrev, die->attr);
+ if (abbrevs[die->abbrev].children) {
+ putdies(die->child);
+ cput(0);
+ }
+}
+
+static void
+reverselist(DWDie** list)
+{
+ DWDie *curr, *prev;
+
+ curr = *list;
+ prev = nil;
+ while(curr != nil) {
+ DWDie* next = curr->link;
+ curr->link = prev;
+ prev = curr;
+ curr = next;
+ }
+ *list = prev;
+}
+
+static void
+reversetree(DWDie** list)
+{
+ DWDie *die;
+
+ reverselist(list);
+ for (die = *list; die != nil; die = die->link)
+ if (abbrevs[die->abbrev].children)
+ reversetree(&die->child);
+}
+
+static void
+newmemberoffsetattr(DWDie *die, int32 offs)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+ if (offs != 0) {
+ block[i++] = DW_OP_consts;
+ i += sleb128enc(offs, block+i);
+ block[i++] = DW_OP_plus;
+ }
+ newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// location expression that evals to a const.
+static void
+newabslocexprattr(DWDie *die, vlong addr)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+ block[i++] = DW_OP_constu;
+ i += uleb128enc(addr, block+i);
+ newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+// Decoding the type.* symbols. This has to be in sync with
+// ../../pkg/runtime/type.go, or more specificaly, with what
+// ../gc/reflect.c stuffs in these.
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat,
+ KindFloat32,
+ KindFloat64,
+ KindComplex,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+static Reloc*
+decode_reloc(Sym *s, int32 off)
+{
+ int i;
+
+ for (i = 0; i < s->nr; i++)
+ if (s->r[i].off == off)
+ return s->r + i;
+ return nil;
+}
+
+static uvlong
+decode_inuxi(uchar* p, int sz)
+{
+ uint64 v;
+ uint32 l;
+ uchar *cast, *inuxi;
+ int i;
+
+ v = l = 0;
+ cast = nil;
+ inuxi = nil;
+ switch (sz) {
+ case 2:
+ cast = (uchar*)&l;
+ inuxi = inuxi2;
+ break;
+ case 4:
+ cast = (uchar*)&l;
+ inuxi = inuxi4;
+ break;
+ case 8:
+ cast = (uchar*)&v;
+ inuxi = inuxi8;
+ break;
+ default:
+ diag("decode inuxi %d", sz);
+ errorexit();
+ }
+ for (i = 0; i < sz; i++)
+ cast[inuxi[i]] = p[i];
+ if (sz == 8)
+ return v;
+ return l;
+}
+
+// Type.commonType.kind
+static uint8
+decodetype_kind(Sym *s)
+{
+ return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
+}
+
+// Type.commonType.size
+static vlong
+decodetype_size(Sym *s)
+{
+ return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10
+}
+
+// Type.ArrayType.elem and Type.SliceType.Elem
+static Sym*
+decodetype_arrayelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+static vlong
+decodetype_arraylen(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, PtrSize);
+}
+
+// Type.PtrType.elem
+static Sym*
+decodetype_ptrelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+static Sym*
+decodetype_mapkey(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+static Sym*
+decodetype_mapvalue(Sym *s)
+{
+ return decode_reloc(s, 6*PtrSize + 8)->sym; // 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+static Sym*
+decodetype_chanelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+static int
+decodetype_funcdotdotdot(Sym *s)
+{
+ return s->p[5*PtrSize + 8];
+}
+
+// Type.FuncType.in.len
+static int
+decodetype_funcincount(Sym *s)
+{
+ return decode_inuxi(s->p + 7*PtrSize + 8, 4);
+}
+
+static int
+decodetype_funcoutcount(Sym *s)
+{
+ return decode_inuxi(s->p + 8*PtrSize + 16, 4);
+}
+
+static Sym*
+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;
+}
+
+static Sym*
+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;
+}
+
+// Type.StructType.fields.Slice::len
+static int
+decodetype_structfieldcount(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, 4); // 0x20 / 0x38
+}
+
+// Type.StructType.fields[]-> name, typ and offset. sizeof(structField) = 5*PtrSize
+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.
+ return nil;
+ r = decode_reloc(r->sym, 0); // string."foo"
+ if (r == nil) // shouldn't happen.
+ return nil;
+ return (char*)r->sym->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
+}
+
+static vlong
+decodetype_structfieldoffs(Sym *s, int i)
+{
+ return decode_inuxi(s->p + 10*PtrSize + 0x10 + i*5*PtrSize, 4); // 0x38 / 0x60
+}
+
+// InterfaceTYpe.methods.len
+static vlong
+decodetype_ifacemethodcount(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, 4);
+}
+
+
+// Fake attributes for slices, maps and channel
+enum {
+ DW_AT_internal_elem_type = 250, // channels and slices
+ DW_AT_internal_key_type = 251, // maps
+ DW_AT_internal_val_type = 252, // maps
+ DW_AT_internal_location = 253, // params and locals
+};
+
+static DWDie* defptrto(DWDie *dwtype); // below
+
+// Define gotype, for composite ones recurse into constituents.
+static DWDie*
+defgotype(Sym *gotype)
+{
+ DWDie *die, *fld;
+ Sym *s;
+ char *name, *f;
+ uint8 kind;
+ vlong bytesize;
+ int i, nfields;
+
+ if (gotype == nil)
+ return find_or_diag(&dwtypes, "<unspecified>");
+
+ if (strncmp("type.", gotype->name, 5) != 0) {
+ 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
+
+ die = find(&dwtypes, name);
+ if (die != nil)
+ return die;
+
+ if (0 && debug['v'] > 2) {
+ print("new type: %s @0x%08x [%d]", gotype->name, gotype->value, gotype->size);
+ for (i = 0; i < gotype->size; i++) {
+ if (!(i%8)) print("\n\t%04x ", i);
+ print("%02x ", gotype->p[i]);
+ }
+ print("\n");
+ for (i = 0; i < gotype->nr; i++) {
+ print("\t0x%02x[%x] %d %s[%llx]\n",
+ gotype->r[i].off,
+ gotype->r[i].siz,
+ gotype->r[i].type,
+ gotype->r[i].sym->name,
+ (vlong)gotype->r[i].add);
+ }
+ }
+
+ kind = decodetype_kind(gotype);
+ bytesize = decodetype_size(gotype);
+
+ switch (kind) {
+ case KindBool:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindInt:
+ case KindInt8:
+ case KindInt16:
+ case KindInt32:
+ case KindInt64:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindUint:
+ case KindUint8:
+ case KindUint16:
+ case KindUint32:
+ case KindUint64:
+ case KindUintptr:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+ 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);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0);
+ 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);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindArray:
+ die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_arrayelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ fld = newdie(die, DW_ABRV_ARRAYRANGE, "range");
+ newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0);
+ newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+ break;
+
+ case KindChan:
+ die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_chanelem(gotype);
+ newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
+ break;
+
+ case KindFunc:
+ die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+ newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
+ nfields = decodetype_funcincount(gotype);
+ for (i = 0; i < nfields; i++) {
+ s = decodetype_funcintype(gotype, i);
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+ newrefattr(fld, DW_AT_type, defgotype(s));
+ }
+ if (decodetype_funcdotdotdot(gotype))
+ newdie(die, DW_ABRV_DOTDOTDOT, "...");
+ nfields = decodetype_funcoutcount(gotype);
+ for (i = 0; i < nfields; i++) {
+ s = decodetype_funcouttype(gotype, i);
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+ newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
+ }
+ die = defptrto(die);
+ break;
+
+ case KindInterface:
+ die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ nfields = decodetype_ifacemethodcount(gotype);
+ if (nfields == 0)
+ s = lookup("type.runtime.eface", 0);
+ else
+ s = lookup("type.runtime.iface", 0);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindMap:
+ die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
+ s = decodetype_mapkey(gotype);
+ newrefattr(die, DW_AT_internal_key_type, defgotype(s));
+ s = decodetype_mapvalue(gotype);
+ newrefattr(die, DW_AT_internal_val_type, defgotype(s));
+ break;
+
+ case KindPtr:
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ s = decodetype_ptrelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindSlice:
+ die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_arrayelem(gotype);
+ newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
+ break;
+
+ case KindString:
+ die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindStruct:
+ die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ nfields = decodetype_structfieldcount(gotype);
+ for (i = 0; i < nfields; i++) {
+ f = decodetype_structfieldname(gotype, i);
+ s = decodetype_structfieldtype(gotype, i);
+ if (f == nil)
+ f = s->name + 5; // skip "type."
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
+ newrefattr(fld, DW_AT_type, defgotype(s));
+ newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
+ }
+ break;
+
+ case KindUnsafePointer:
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+ break;
+
+ default:
+ diag("definition of unknown kind %d: %s", kind, gotype->name);
+ die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
+ newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
+ }
+
+ return die;
+}
+
+// Find or construct *T given T.
+static DWDie*
+defptrto(DWDie *dwtype)
+{
+ char ptrname[1024];
+ DWDie *die;
+
+ snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
+ die = find(&dwtypes, ptrname);
+ if (die == nil) {
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
+ strcpy(mal(strlen(ptrname)+1), ptrname));
+ newrefattr(die, DW_AT_type, dwtype);
+ }
+ return die;
+}
+
+// Copies src's children into dst. Copies attributes by value.
+// DWAttr.data is copied as pointer only.
+static void
+copychildren(DWDie *dst, DWDie *src)
+{
+ DWDie *c;
+ DWAttr *a;
+
+ for (src = src->child; src != nil; src = src->link) {
+ c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
+ for (a = src->attr; a != nil; a = a->link)
+ newattr(c, a->atr, a->cls, a->value, a->data);
+ copychildren(c, src);
+ }
+ reverselist(&dst->child);
+}
+
+// Search children (assumed to have DW_TAG_member) for the one named
+// field and set it's DW_AT_type to dwtype
+static void
+substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
+{
+ DWDie *child;
+ DWAttr *a;
+
+ child = find_or_diag(structdie, field);
+ if (child == nil)
+ return;
+
+ a = getattr(child, DW_AT_type);
+ if (a != nil)
+ a->data = (char*) dwtype;
+ else
+ newrefattr(child, DW_AT_type, dwtype);
+}
+
+static void
+synthesizestringtypes(DWDie* die)
+{
+ DWDie *prototype;
+
+ prototype = defgotype(lookup("type.runtime.string_", 0));
+ if (prototype == nil)
+ return;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_STRINGTYPE)
+ continue;
+ copychildren(die, prototype);
+ }
+}
+
+static void
+synthesizeslicetypes(DWDie *die)
+{
+ DWDie *prototype, *elem;
+
+ prototype = defgotype(lookup("type.runtime.slice",0));
+ if (prototype == nil)
+ return;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_SLICETYPE)
+ continue;
+ copychildren(die, prototype);
+ elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
+ substitutetype(die, "array", defptrto(elem));
+ }
+}
+
+static char*
+mkinternaltypename(char *base, char *arg1, char *arg2)
+{
+ char buf[1024];
+ char *n;
+
+ if (arg2 == nil)
+ snprint(buf, sizeof buf, "%s<%s>", base, arg1);
+ else
+ snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
+ n = mal(strlen(buf) + 1);
+ memmove(n, buf, strlen(buf));
+ return n;
+}
+
+
+// synthesizemaptypes is way too closely married to runtime/hashmap.c
+enum {
+ MaxValsize = 256 - 64
+};
+
+static void
+synthesizemaptypes(DWDie *die)
+{
+
+ DWDie *hash, *hash_subtable, *hash_entry,
+ *dwh, *dwhs, *dwhe, *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));
+
+ 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)
+ return;
+
+ hashsize = getattr(dwh, DW_AT_byte_size)->value;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_MAPTYPE)
+ continue;
+
+ keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data;
+ valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data;
+
+ a = getattr(keytype, DW_AT_byte_size);
+ keysize = a ? a->value : PtrSize; // We don't store size with Pointers
+
+ a = getattr(valtype, DW_AT_byte_size);
+ valsize = a ? a->value : PtrSize;
+
+ // This is what happens in hash_init and makemap_c
+ valsize_in_hash = valsize;
+ if (valsize > MaxValsize)
+ valsize_in_hash = PtrSize;
+ datavo = keysize;
+ if (valsize_in_hash >= PtrSize)
+ datavo = rnd(keysize, PtrSize);
+ datsize = datavo + valsize_in_hash;
+ if (datsize < PtrSize)
+ datsize = PtrSize;
+ datsize = rnd(datsize, PtrSize);
+
+ // Construct struct hash_entry<K,V>
+ dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash_entry",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwhe, hash_entry);
+ substitutetype(dwhe, "key", keytype);
+ if (valsize > MaxValsize)
+ valtype = defptrto(valtype);
+ substitutetype(dwhe, "val", valtype);
+ fld = find_or_diag(dwhe, "val");
+ delattr(fld, DW_AT_data_member_location);
+ newmemberoffsetattr(fld, hashsize + datavo);
+ newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
+
+ // Construct hash_subtable<hash_entry<K,V>>
+ dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash_subtable",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwhs, hash_subtable);
+ substitutetype(dwhs, "end", defptrto(dwhe));
+ substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
+ newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hash_subtable, DW_AT_byte_size)->value, NULL);
+
+ // Construct hash<K,V>
+ dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwh, hash);
+ substitutetype(dwh, "st", defptrto(dwhs));
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hash, DW_AT_byte_size)->value, NULL);
+
+ newrefattr(die, DW_AT_type, defptrto(dwh));
+ }
+}
+
+static void
+synthesizechantypes(DWDie *die)
+{
+ DWDie *sudog, *waitq, *link, *hchan,
+ *dws, *dww, *dwl, *dwh, *elemtype;
+ 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));
+ if (sudog == nil || waitq == nil || link == nil || hchan == nil)
+ return;
+
+ sudogsize = getattr(sudog, DW_AT_byte_size)->value;
+ linksize = getattr(link, DW_AT_byte_size)->value;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_CHANTYPE)
+ continue;
+ elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
+ a = getattr(elemtype, DW_AT_byte_size);
+ elemsize = a ? a->value : PtrSize;
+
+ // sudog<T>
+ dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("sudog",
+ getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dws, sudog);
+ substitutetype(dws, "elem", elemtype);
+ newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
+ sudogsize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+
+ // waitq<T>
+ dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dww, waitq);
+ substitutetype(dww, "first", defptrto(dws));
+ substitutetype(dww, "last", defptrto(dws));
+ newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(waitq, DW_AT_byte_size)->value, NULL);
+
+ // link<T>
+ dwl = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("link", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dwl, link);
+ substitutetype(dwl, "link", defptrto(dwl));
+ substitutetype(dwl, "elem", elemtype);
+ newattr(dwl, DW_AT_byte_size, DW_CLS_CONSTANT,
+ linksize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+
+ // hchan<T>
+ dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dwh, hchan);
+ substitutetype(dwh, "senddataq", defptrto(dwl));
+ substitutetype(dwh, "recvdataq", defptrto(dwl));
+ substitutetype(dwh, "recvq", dww);
+ substitutetype(dwh, "sendq", dww);
+ substitutetype(dwh, "free", dws);
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hchan, DW_AT_byte_size)->value, NULL);
+
+ newrefattr(die, DW_AT_type, defptrto(dwh));
+ }
+}
+
+// For use with pass.c::genasmsym
+static void
+defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
+{
+ DWDie *dv, *dt;
+
+ if (strncmp(s, "go.string.", 10) == 0)
+ return;
+ if (strncmp(s, "string.", 7) == 0)
+ return;
+ if (strncmp(s, "type._.", 7) == 0)
+ return;
+
+ if (strncmp(s, "type.", 5) == 0) {
+ defgotype(sym);
+ return;
+ }
+
+ dv = nil;
+
+ switch (t) {
+ default:
+ return;
+ case 'd':
+ case 'b':
+ case 'D':
+ case 'B':
+ dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
+ newabslocexprattr(dv, v);
+ if (ver == 0)
+ newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
+ // fallthrough
+ case 'a':
+ case 'p':
+ dt = defgotype(gotype);
+ }
+
+ if (dv != nil)
+ newrefattr(dv, DW_AT_type, dt);
+}
+
+// TODO(lvd) For now, just append them all to the first compilation
+// unit (that should be main), in the future distribute them to the
+// appropriate compilation units.
+static void
+movetomodule(DWDie *parent)
+{
+ DWDie *die;
+
+ for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
+ die->link = parent->child;
+}
+
+/*
+ * Filename fragments for the line history stack.
+ */
+
+static char **ftab;
+static int ftabsize;
+
+void
+dwarfaddfrag(int n, char *frag)
+{
+ int s;
+
+ if (n >= ftabsize) {
+ s = ftabsize;
+ ftabsize = 1 + n + (n >> 2);
+ ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
+ memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
+ }
+
+ if (*frag == '<')
+ frag++;
+ ftab[n] = frag;
+}
+
+// Returns a malloc'ed string, piecewise copied from the ftab.
+static char *
+decodez(char *s)
+{
+ int len, o;
+ char *ss, *f;
+ char *r, *rb, *re;
+
+ len = 0;
+ ss = s + 1; // first is 0
+ while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
+ if (o < 0 || o >= ftabsize) {
+ diag("corrupt z entry");
+ return 0;
+ }
+ f = ftab[o];
+ if (f == nil) {
+ diag("corrupt z entry");
+ return 0;
+ }
+ len += strlen(f) + 1; // for the '/'
+ ss += 2;
+ }
+
+ if (len == 0)
+ return 0;
+
+ r = malloc(len + 1);
+ rb = r;
+ re = rb + len + 1;
+
+ s++;
+ while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
+ f = ftab[o];
+ if (rb == r || rb[-1] == '/')
+ rb = seprint(rb, re, "%s", f);
+ else
+ rb = seprint(rb, re, "/%s", f);
+ s += 2;
+ }
+ return r;
+}
+
+/*
+ * The line history itself
+ */
+
+static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
+static int histfilesize;
+static int histfilecap;
+
+static void
+clearhistfile(void)
+{
+ int i;
+
+ // [0] holds "<eof>"
+ for (i = 1; i < histfilesize; i++)
+ free(histfile[i]);
+ histfilesize = 0;
+}
+
+static int
+addhistfile(char *zentry)
+{
+ char *fname;
+
+ if (histfilesize == histfilecap) {
+ histfilecap = 2 * histfilecap + 2;
+ histfile = realloc(histfile, histfilecap * sizeof(char*));
+ }
+ if (histfilesize == 0)
+ histfile[histfilesize++] = "<eof>";
+
+ fname = decodez(zentry);
+ if (fname == 0)
+ return -1;
+ // Don't fill with duplicates (check only top one).
+ if (strcmp(fname, histfile[histfilesize-1]) == 0) {
+ free(fname);
+ return histfilesize - 1;
+ }
+ histfile[histfilesize++] = fname;
+ return histfilesize - 1;
+}
+
+// if the histfile stack contains ..../runtime/runtime_defs.go
+// use that to set gdbscript
+static void
+finddebugruntimepath()
+{
+ int i, l;
+ char *c;
+
+ for (i = 1; i < histfilesize; i++) {
+ if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) {
+ l = c - histfile[i];
+ memmove(gdbscript, histfile[i], l);
+ memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1);
+ break;
+ }
+ }
+}
+
+// Go's runtime C sources are sane, and Go sources nest only 1 level,
+// so 16 should be plenty.
+static struct {
+ int file;
+ vlong line;
+} includestack[16];
+static int includetop;
+static vlong absline;
+
+typedef struct Linehist Linehist;
+struct Linehist {
+ Linehist *link;
+ vlong absline;
+ vlong line;
+ int file;
+};
+
+static Linehist *linehist;
+
+static void
+checknesting(void)
+{
+ int i;
+
+ if (includetop < 0) {
+ diag("corrupt z stack");
+ errorexit();
+ }
+ if (includetop >= nelem(includestack)) {
+ diag("nesting too deep");
+ for (i = 0; i < nelem(includestack); i++)
+ diag("\t%s", histfile[includestack[i].file]);
+ errorexit();
+ }
+}
+
+/*
+ * Return false if the a->link chain contains no history, otherwise
+ * returns true and finds z and Z entries in the Auto list (of a
+ * Prog), and resets the history stack
+ */
+static int
+inithist(Auto *a)
+{
+ Linehist *lh;
+
+ for (; a; a = a->link)
+ if (a->type == D_FILE)
+ break;
+ if (a==nil)
+ return 0;
+
+ // We have a new history. They are guaranteed to come completely
+ // at the beginning of the compilation unit.
+ if (a->aoffset != 1) {
+ diag("stray 'z' with offset %d", a->aoffset);
+ return 0;
+ }
+
+ // Clear the history.
+ clearhistfile();
+ includetop = 0;
+ includestack[includetop].file = 0;
+ includestack[includetop].line = -1;
+ absline = 0;
+ while (linehist != nil) {
+ lh = linehist->link;
+ free(linehist);
+ linehist = lh;
+ }
+
+ // Construct the new one.
+ for (; a; a = a->link) {
+ if (a->type == D_FILE) { // 'z'
+ int f = addhistfile(a->asym->name);
+ if (f < 0) { // pop file
+ includetop--;
+ checknesting();
+ } else if(f != includestack[includetop].file) { // pushed a new file
+ includestack[includetop].line += a->aoffset - absline;
+ includetop++;
+ checknesting();
+ includestack[includetop].file = f;
+ includestack[includetop].line = 1;
+ }
+ absline = a->aoffset;
+ } else if (a->type == D_FILE1) { // 'Z'
+ // We could just fixup the current
+ // linehist->line, but there doesn't appear to
+ // be a guarantee that every 'Z' is preceded
+ // by it's own 'z', so do the safe thing and
+ // update the stack and push a new Linehist
+ // entry
+ includestack[includetop].line = a->aoffset;
+ } else
+ continue;
+ if (linehist == 0 || linehist->absline != absline) {
+ Linehist* lh = malloc(sizeof *lh);
+ lh->link = linehist;
+ lh->absline = absline;
+ linehist = lh;
+ }
+ linehist->file = includestack[includetop].file;
+ linehist->line = includestack[includetop].line;
+ }
+ return 1;
+}
+
+static Linehist *
+searchhist(vlong absline)
+{
+ Linehist *lh;
+
+ for (lh = linehist; lh; lh = lh->link)
+ if (lh->absline <= absline)
+ break;
+ return lh;
+}
+
+static int
+guesslang(char *s)
+{
+ if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
+ return DW_LANG_Go;
+
+ return DW_LANG_C;
+}
+
+/*
+ * Generate short opcodes when possible, long ones when neccesary.
+ * See section 6.2.5
+ */
+
+enum {
+ LINE_BASE = -1,
+ LINE_RANGE = 4,
+ OPCODE_BASE = 5
+};
+
+static void
+putpclcdelta(vlong delta_pc, vlong delta_lc)
+{
+ if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
+ vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
+ if (OPCODE_BASE <= opcode && opcode < 256) {
+ cput(opcode);
+ return;
+ }
+ }
+
+ if (delta_pc) {
+ cput(DW_LNS_advance_pc);
+ sleb128put(delta_pc);
+ }
+
+ cput(DW_LNS_advance_line);
+ sleb128put(delta_lc);
+ cput(DW_LNS_copy);
+}
+
+static void
+newcfaoffsetattr(DWDie *die, int32 offs)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+
+ block[i++] = DW_OP_call_frame_cfa;
+ if (offs != 0) {
+ block[i++] = DW_OP_consts;
+ i += sleb128enc(offs, block+i);
+ block[i++] = DW_OP_plus;
+ }
+ newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+static char*
+mkvarname(char* name, int da)
+{
+ char buf[1024];
+ char *n;
+
+ snprint(buf, sizeof buf, "%s#%d", name, da);
+ n = mal(strlen(buf) + 1);
+ memmove(n, buf, strlen(buf));
+ return n;
+}
+
+/*
+ * Walk prog table, emit line program and build DIE tree.
+ */
+
+// flush previous compilation unit.
+static void
+flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
+{
+ vlong here;
+
+ if (dwinfo != nil && pc != 0) {
+ newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
+ }
+
+ if (unitstart >= 0) {
+ cput(0); // start extended opcode
+ uleb128put(1);
+ cput(DW_LNE_end_sequence);
+ cflush();
+
+ here = cpos();
+ seek(cout, unitstart, 0);
+ LPUT(here - unitstart - sizeof(int32));
+ cflush();
+ seek(cout, here, 0);
+ }
+}
+
+static void
+writelines(void)
+{
+ Prog *q;
+ Sym *s;
+ Auto *a;
+ vlong unitstart, offs;
+ vlong pc, epc, lc, llc, lline;
+ int currfile;
+ int i, lang, da, dt;
+ Linehist *lh;
+ DWDie *dwinfo, *dwfunc, *dwvar, **dws;
+ DWDie *varhash[HASHSIZE];
+ char *n, *nn;
+
+ unitstart = -1;
+ epc = pc = 0;
+ lc = 1;
+ llc = 1;
+ currfile = -1;
+ lineo = cpos();
+ dwinfo = nil;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ s = cursym;
+ if(s->text == P)
+ continue;
+
+ // Look for history stack. If we find one,
+ // we're entering a new compilation unit
+
+ if (inithist(s->autom)) {
+ flushunit(dwinfo, epc, unitstart);
+ unitstart = cpos();
+
+ if(debug['v'] > 1) {
+ print("dwarf writelines found %s\n", histfile[1]);
+ Linehist* lh;
+ for (lh = linehist; lh; lh = lh->link)
+ print("\t%8lld: [%4lld]%s\n",
+ lh->absline, lh->line, histfile[lh->file]);
+ }
+
+ lang = guesslang(histfile[1]);
+ finddebugruntimepath();
+
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
+ newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
+ newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
+
+ // Write .debug_line Line Number Program Header (sec 6.2.4)
+ // Fields marked with (*) must be changed for 64-bit dwarf
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(11); // header_length (*), starting here.
+
+ cput(1); // minimum_instruction_length
+ cput(1); // default_is_stmt
+ cput(LINE_BASE); // line_base
+ cput(LINE_RANGE); // line_range
+ cput(OPCODE_BASE); // opcode_base (we only use 1..4)
+ cput(0); // standard_opcode_lengths[1]
+ cput(1); // standard_opcode_lengths[2]
+ cput(1); // standard_opcode_lengths[3]
+ cput(1); // standard_opcode_lengths[4]
+ cput(0); // include_directories (empty)
+ cput(0); // file_names (empty) (emitted by DW_LNE's below)
+ // header_length ends here.
+
+ for (i=1; i < histfilesize; i++) {
+ cput(0); // start extended opcode
+ uleb128put(1 + strlen(histfile[i]) + 4);
+ cput(DW_LNE_define_file);
+ strnput(histfile[i], strlen(histfile[i]) + 4);
+ // 4 zeros: the string termination + 3 fields.
+ }
+
+ epc = pc = s->text->pc;
+ currfile = 1;
+ lc = 1;
+ llc = 1;
+
+ cput(0); // start extended opcode
+ uleb128put(1 + PtrSize);
+ cput(DW_LNE_set_address);
+ addrput(pc);
+ }
+ if(s->text == nil)
+ continue;
+
+ if (unitstart < 0) {
+ diag("reachable code before seeing any history: %P", s->text);
+ continue;
+ }
+
+ dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
+ newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
+ epc = s->value + s->size;
+ newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ if (s->version == 0)
+ newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
+
+ if(s->text->link == nil)
+ continue;
+
+ for(q = s->text; q != P; q = q->link) {
+ lh = searchhist(q->line);
+ if (lh == nil) {
+ diag("corrupt history or bad absolute line: %P", q);
+ continue;
+ }
+
+ if (lh->file < 1) { // 0 is the past-EOF entry.
+ // diag("instruction with line number past EOF in %s: %P", histfile[1], q);
+ continue;
+ }
+
+ lline = lh->line + q->line - lh->absline;
+ if (debug['v'] > 1)
+ print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
+
+ if (q->line == lc)
+ continue;
+ if (currfile != lh->file) {
+ currfile = lh->file;
+ cput(DW_LNS_set_file);
+ uleb128put(currfile);
+ }
+ putpclcdelta(q->pc - pc, lline - llc);
+ pc = q->pc;
+ lc = q->line;
+ llc = lline;
+ }
+
+ da = 0;
+ dwfunc->hash = varhash; // enable indexing of children by name
+ memset(varhash, 0, sizeof varhash);
+ for(a = s->autom; a; a = a->link) {
+ switch (a->type) {
+ case D_AUTO:
+ dt = DW_ABRV_AUTO;
+ offs = a->aoffset - PtrSize;
+ break;
+ case D_PARAM:
+ dt = DW_ABRV_PARAM;
+ offs = a->aoffset;
+ break;
+ default:
+ continue;
+ }
+ if (strstr(a->asym->name, ".autotmp_"))
+ continue;
+ if (find(dwfunc, a->asym->name) != nil)
+ n = mkvarname(a->asym->name, da);
+ else
+ n = a->asym->name;
+ // Drop the package prefix from locals and arguments.
+ nn = strrchr(n, '.');
+ if (nn)
+ n = nn + 1;
+
+ dwvar = newdie(dwfunc, dt, n);
+ newcfaoffsetattr(dwvar, offs);
+ newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
+
+ // push dwvar down dwfunc->child to preserve order
+ newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, NULL);
+ dwfunc->child = dwvar->link; // take dwvar out from the top of the list
+ for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
+ if (offs > getattr(*dws, DW_AT_internal_location)->value)
+ break;
+ dwvar->link = *dws;
+ *dws = dwvar;
+
+ da++;
+ }
+
+ dwfunc->hash = nil;
+ }
+
+ flushunit(dwinfo, epc, unitstart);
+ linesize = cpos() - lineo;
+}
+
+/*
+ * Emit .debug_frame
+ */
+enum
+{
+ CIERESERVE = 16,
+ DATAALIGNMENTFACTOR = -4, // TODO -PtrSize?
+ FAKERETURNCOLUMN = 16 // TODO gdb6 doesnt like > 15?
+};
+
+static void
+putpccfadelta(vlong deltapc, vlong cfa)
+{
+ if (deltapc < 0x40) {
+ cput(DW_CFA_advance_loc + deltapc);
+ } else if (deltapc < 0x100) {
+ cput(DW_CFA_advance_loc1);
+ cput(deltapc);
+ } else if (deltapc < 0x10000) {
+ cput(DW_CFA_advance_loc2);
+ WPUT(deltapc);
+ } else {
+ cput(DW_CFA_advance_loc4);
+ LPUT(deltapc);
+ }
+
+ cput(DW_CFA_def_cfa_offset_sf);
+ sleb128put(cfa / DATAALIGNMENTFACTOR);
+}
+
+static void
+writeframes(void)
+{
+ Prog *p, *q;
+ Sym *s;
+ vlong fdeo, fdesize, pad, cfa, pc;
+
+ frameo = cpos();
+
+ // Emit the CIE, Section 6.4.1
+ LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
+ LPUT(0xffffffff); // cid.
+ cput(3); // dwarf version (appendix F)
+ cput(0); // augmentation ""
+ uleb128put(1); // code_alignment_factor
+ sleb128put(DATAALIGNMENTFACTOR); // guess
+ uleb128put(FAKERETURNCOLUMN); // return_address_register
+
+ cput(DW_CFA_def_cfa);
+ uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
+ uleb128put(PtrSize); // offset
+
+ cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address
+ uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
+
+ // 4 is to exclude the length field.
+ pad = CIERESERVE + frameo + 4 - cpos();
+ if (pad < 0) {
+ diag("CIERESERVE too small by %lld bytes.", -pad);
+ errorexit();
+ }
+ strnput("", pad);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ s = cursym;
+ if(s->text == nil)
+ continue;
+
+ fdeo = cpos();
+ // Emit a FDE, Section 6.4.1, starting wit a placeholder.
+ LPUT(0); // length, must be multiple of PtrSize
+ LPUT(0); // Pointer to the CIE above, at offset 0
+ addrput(0); // initial location
+ addrput(0); // address range
+
+ cfa = PtrSize; // CFA starts at sp+PtrSize
+ p = s->text;
+ pc = p->pc;
+
+ for(q = p; q->link != P; q = q->link) {
+ if (q->spadj == 0)
+ continue;
+ cfa += q->spadj;
+ putpccfadelta(q->link->pc - pc, cfa);
+ pc = q->link->pc;
+ }
+
+ fdesize = cpos() - fdeo - 4; // exclude the length field.
+ pad = rnd(fdesize, PtrSize) - fdesize;
+ strnput("", pad);
+ fdesize += pad;
+ cflush();
+
+ // Emit the FDE header for real, Section 6.4.1.
+ seek(cout, fdeo, 0);
+ LPUT(fdesize);
+ LPUT(0);
+ addrput(p->pc);
+ addrput(s->size);
+
+ cflush();
+ seek(cout, fdeo + 4 + fdesize, 0);
+ }
+
+ cflush();
+ framesize = cpos() - frameo;
+}
+
+/*
+ * Walk DWarfDebugInfoEntries, and emit .debug_info
+ */
+enum
+{
+ COMPUNITHEADERSIZE = 4+2+4+1
+};
+
+static void
+writeinfo(void)
+{
+ DWDie *compunit;
+ vlong unitstart, here;
+
+ fwdcount = 0;
+
+ for (compunit = dwroot.child; compunit; compunit = compunit->link) {
+ unitstart = cpos();
+
+ // Write .debug_info Compilation Unit Header (sec 7.5.1)
+ // Fields marked with (*) must be changed for 64-bit dwarf
+ // This must match COMPUNITHEADERSIZE above.
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(0); // debug_abbrev_offset (*)
+ cput(PtrSize); // address_size
+
+ putdie(compunit);
+
+ cflush();
+ here = cpos();
+ seek(cout, unitstart, 0);
+ LPUT(here - unitstart - 4); // exclude the length field.
+ cflush();
+ seek(cout, here, 0);
+ }
+
+}
+
+/*
+ * Emit .debug_pubnames/_types. _info must have been written before,
+ * because we need die->offs and infoo/infosize;
+ */
+static int
+ispubname(DWDie *die) {
+ DWAttr *a;
+
+ switch(die->abbrev) {
+ case DW_ABRV_FUNCTION:
+ case DW_ABRV_VARIABLE:
+ a = getattr(die, DW_AT_external);
+ return a && a->value;
+ }
+ return 0;
+}
+
+static int
+ispubtype(DWDie *die) {
+ return die->abbrev >= DW_ABRV_NULLTYPE;
+}
+
+static vlong
+writepub(int (*ispub)(DWDie*))
+{
+ DWDie *compunit, *die;
+ DWAttr *dwa;
+ vlong unitstart, unitend, sectionstart, here;
+
+ sectionstart = cpos();
+
+ for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+ unitstart = compunit->offs - COMPUNITHEADERSIZE;
+ if (compunit->link != nil)
+ unitend = compunit->link->offs - COMPUNITHEADERSIZE;
+ else
+ unitend = infoo + infosize;
+
+ // Write .debug_pubnames/types Header (sec 6.1.1)
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(unitstart); // debug_info_offset (of the Comp unit Header)
+ LPUT(unitend - unitstart); // debug_info_length
+
+ for (die = compunit->child; die != nil; die = die->link) {
+ if (!ispub(die)) continue;
+ LPUT(die->offs - unitstart);
+ dwa = getattr(die, DW_AT_name);
+ strnput(dwa->data, dwa->value + 1);
+ }
+ LPUT(0);
+
+ cflush();
+ here = cpos();
+ seek(cout, sectionstart, 0);
+ LPUT(here - sectionstart - 4); // exclude the length field.
+ cflush();
+ seek(cout, here, 0);
+
+ }
+
+ return sectionstart;
+}
+
+/*
+ * emit .debug_aranges. _info must have been written before,
+ * because we need die->offs of dw_globals.
+ */
+static vlong
+writearanges(void)
+{
+ DWDie *compunit;
+ DWAttr *b, *e;
+ int headersize;
+ vlong sectionstart;
+
+ sectionstart = cpos();
+ headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
+
+ for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+ b = getattr(compunit, DW_AT_low_pc);
+ if (b == nil)
+ continue;
+ e = getattr(compunit, DW_AT_high_pc);
+ if (e == nil)
+ continue;
+
+ // Write .debug_aranges Header + entry (sec 6.1.2)
+ LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset
+ cput(PtrSize); // address_size
+ cput(0); // segment_size
+ strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
+
+ addrput(b->value);
+ addrput(e->value - b->value);
+ addrput(0);
+ addrput(0);
+ }
+ cflush();
+ return sectionstart;
+}
+
+static vlong
+writegdbscript(void)
+{
+ vlong sectionstart;
+
+ sectionstart = cpos();
+
+ if (gdbscript[0]) {
+ cput(1); // magic 1 byte?
+ strnput(gdbscript, strlen(gdbscript)+1);
+ cflush();
+ }
+ return sectionstart;
+}
+
+/*
+ * This is the main entry point for generating dwarf. After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section. When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
+void
+dwarfemitdebugsections(void)
+{
+ vlong infoe;
+ DWDie* die;
+
+ // For diagnostic messages.
+ newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
+
+ mkindex(&dwroot);
+ mkindex(&dwtypes);
+ mkindex(&dwglobals);
+
+ // Some types that must exist to define other ones.
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
+ newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"),
+ DW_AT_type, find(&dwtypes, "void"));
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+ 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));
+
+ genasmsym(defdwsymb);
+
+ writeabbrev();
+ writelines();
+ writeframes();
+
+ synthesizestringtypes(dwtypes.child);
+ synthesizeslicetypes(dwtypes.child);
+ synthesizemaptypes(dwtypes.child);
+ synthesizechantypes(dwtypes.child);
+
+ reversetree(&dwroot.child);
+ reversetree(&dwtypes.child);
+ reversetree(&dwglobals.child);
+
+ movetomodule(&dwtypes);
+ movetomodule(&dwglobals);
+
+ infoo = cpos();
+ writeinfo();
+ gdbscripto = arangeso = pubtypeso = pubnameso = infoe = cpos();
+
+ if (fwdcount > 0) {
+ if (debug['v'])
+ Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
+ seek(cout, infoo, 0);
+ writeinfo();
+ if (fwdcount > 0) {
+ diag("unresolved references after first dwarf info pass");
+ errorexit();
+ }
+ if (infoe != cpos()) {
+ diag("inconsistent second dwarf info pass");
+ errorexit();
+ }
+ }
+ infosize = infoe - infoo;
+
+ pubnameso = writepub(ispubname);
+ pubtypeso = writepub(ispubtype);
+ arangeso = writearanges();
+ gdbscripto = writegdbscript();
+
+ pubnamessize = pubtypeso - pubnameso;
+ pubtypessize = arangeso - pubtypeso;
+ arangessize = gdbscripto - arangeso;
+ gdbscriptsize = cpos() - gdbscripto;
+}
+
+/*
+ * Elf.
+ */
+enum
+{
+ ElfStrDebugAbbrev,
+ ElfStrDebugAranges,
+ ElfStrDebugFrame,
+ ElfStrDebugInfo,
+ ElfStrDebugLine,
+ ElfStrDebugLoc,
+ ElfStrDebugMacinfo,
+ ElfStrDebugPubNames,
+ ElfStrDebugPubTypes,
+ ElfStrDebugRanges,
+ ElfStrDebugStr,
+ ElfStrGDBScripts,
+ NElfStrDbg
+};
+
+vlong elfstrdbg[NElfStrDbg];
+
+void
+dwarfaddshstrings(Sym *shstrtab)
+{
+ elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev");
+ elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges");
+ elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame");
+ elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info");
+ elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line");
+ elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc");
+ elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo");
+ elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
+ elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
+ elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
+ elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
+ elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
+}
+
+void
+dwarfaddelfheaders(void)
+{
+ ElfShdr *sh;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
+ sh->type = SHT_PROGBITS;
+ sh->off = abbrevo;
+ sh->size = abbrevsize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
+ sh->type = SHT_PROGBITS;
+ sh->off = lineo;
+ sh->size = linesize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
+ sh->type = SHT_PROGBITS;
+ sh->off = frameo;
+ sh->size = framesize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
+ sh->type = SHT_PROGBITS;
+ sh->off = infoo;
+ sh->size = infosize;
+ sh->addralign = 1;
+
+ if (pubnamessize > 0) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
+ sh->type = SHT_PROGBITS;
+ sh->off = pubnameso;
+ sh->size = pubnamessize;
+ sh->addralign = 1;
+ }
+
+ if (pubtypessize > 0) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
+ sh->type = SHT_PROGBITS;
+ sh->off = pubtypeso;
+ sh->size = pubtypessize;
+ sh->addralign = 1;
+ }
+
+ if (arangessize) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
+ sh->type = SHT_PROGBITS;
+ sh->off = arangeso;
+ sh->size = arangessize;
+ sh->addralign = 1;
+ }
+
+ if (gdbscriptsize) {
+ sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
+ sh->type = SHT_PROGBITS;
+ sh->off = gdbscripto;
+ sh->size = gdbscriptsize;
+ sh->addralign = 1;
+ }
+}
+
+/*
+ * Macho
+ */
+void
+dwarfaddmachoheaders(void)
+{
+ MachoSect *msect;
+ MachoSeg *ms;
+ vlong fakestart;
+ int nsect;
+
+ // Zero vsize segments won't be loaded in memory, even so they
+ // have to be page aligned in the file.
+ fakestart = abbrevo & ~0xfff;
+
+ nsect = 4;
+ if (pubnamessize > 0)
+ nsect++;
+ if (pubtypessize > 0)
+ nsect++;
+ if (arangessize > 0)
+ nsect++;
+ if (gdbscriptsize > 0)
+ nsect++;
+
+ ms = newMachoSeg("__DWARF", nsect);
+ ms->fileoffset = fakestart;
+ ms->filesize = abbrevo-fakestart;
+
+ msect = newMachoSect(ms, "__debug_abbrev");
+ msect->off = abbrevo;
+ msect->size = abbrevsize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_line");
+ msect->off = lineo;
+ msect->size = linesize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_frame");
+ msect->off = frameo;
+ msect->size = framesize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_info");
+ msect->off = infoo;
+ msect->size = infosize;
+ ms->filesize += msect->size;
+
+ if (pubnamessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubnames");
+ msect->off = pubnameso;
+ msect->size = pubnamessize;
+ ms->filesize += msect->size;
+ }
+
+ if (pubtypessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubtypes");
+ msect->off = pubtypeso;
+ msect->size = pubtypessize;
+ ms->filesize += msect->size;
+ }
+
+ if (arangessize > 0) {
+ msect = newMachoSect(ms, "__debug_aranges");
+ msect->off = arangeso;
+ msect->size = arangessize;
+ ms->filesize += msect->size;
+ }
+
+ // TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
+ if (gdbscriptsize > 0) {
+ msect = newMachoSect(ms, "__debug_gdb_scripts");
+ msect->off = gdbscripto;
+ msect->size = gdbscriptsize;
+ ms->filesize += msect->size;
+ }
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
new file mode 100644
index 000000000..7881213c2
--- /dev/null
+++ b/src/cmd/ld/dwarf.h
@@ -0,0 +1,29 @@
+// 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.
+
+/*
+ * Register 'f' symbol file fragments. Doing this while parsing the
+ * .6 input saves a pass over the symbol table later.
+ */
+void dwarfaddfrag(int n, char* frag);
+
+/*
+ * Emit debug_abbrevs, debug_info and debug_line sections to current
+ * offset in cout.
+ */
+void dwarfemitdebugsections(void);
+
+/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab. Prerequisite for
+ * dwarfaddelfheaders().
+ */
+void dwarfaddshstrings(Sym *shstrtab);
+
+/*
+ * Add section headers pointing to the sections emitted in
+ * dwarfemitdebugsections.
+ */
+void dwarfaddelfheaders(void);
+void dwarfaddmachoheaders(void);
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
new file mode 100644
index 000000000..eed143dff
--- /dev/null
+++ b/src/cmd/ld/dwarf_defs.h
@@ -0,0 +1,503 @@
+// 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.
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+enum
+{
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_parameter = 0x2f,
+ DW_TAG_template_value_parameter = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ // Dwarf3
+ DW_TAG_dwarf_procedure = 0x36,
+ DW_TAG_restrict_type = 0x37,
+ DW_TAG_interface_type = 0x38,
+ DW_TAG_namespace = 0x39,
+ DW_TAG_imported_module = 0x3a,
+ DW_TAG_unspecified_type = 0x3b,
+ DW_TAG_partial_unit = 0x3c,
+ DW_TAG_imported_unit = 0x3d,
+ DW_TAG_condition = 0x3f,
+ DW_TAG_shared_type = 0x40,
+ // Dwarf4
+ DW_TAG_type_unit = 0x41,
+ DW_TAG_rvalue_reference_type = 0x42,
+ DW_TAG_template_alias = 0x43,
+
+ // User defined
+ DW_TAG_lo_user = 0x4080,
+ DW_TAG_hi_user = 0xffff,
+
+};
+
+// Table 19
+enum
+{
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01,
+};
+
+// Not from the spec, but logicaly belongs here
+enum
+{
+ DW_CLS_ADDRESS = 0x01,
+ DW_CLS_BLOCK,
+ DW_CLS_CONSTANT,
+ DW_CLS_FLAG,
+ DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
+ DW_CLS_REFERENCE,
+ DW_CLS_STRING
+};
+
+// Table 20
+enum
+{
+ DW_AT_sibling = 0x01, // reference
+ DW_AT_location = 0x02, // block, loclistptr
+ DW_AT_name = 0x03, // string
+ DW_AT_ordering = 0x09, // constant
+ DW_AT_byte_size = 0x0b, // block, constant, reference
+ DW_AT_bit_offset = 0x0c, // block, constant, reference
+ DW_AT_bit_size = 0x0d, // block, constant, reference
+ DW_AT_stmt_list = 0x10, // lineptr
+ DW_AT_low_pc = 0x11, // address
+ DW_AT_high_pc = 0x12, // address
+ DW_AT_language = 0x13, // constant
+ DW_AT_discr = 0x15, // reference
+ DW_AT_discr_value = 0x16, // constant
+ DW_AT_visibility = 0x17, // constant
+ DW_AT_import = 0x18, // reference
+ DW_AT_string_length = 0x19, // block, loclistptr
+ DW_AT_common_reference = 0x1a, // reference
+ DW_AT_comp_dir = 0x1b, // string
+ DW_AT_const_value = 0x1c, // block, constant, string
+ DW_AT_containing_type = 0x1d, // reference
+ DW_AT_default_value = 0x1e, // reference
+ DW_AT_inline = 0x20, // constant
+ DW_AT_is_optional = 0x21, // flag
+ DW_AT_lower_bound = 0x22, // block, constant, reference
+ DW_AT_producer = 0x25, // string
+ DW_AT_prototyped = 0x27, // flag
+ DW_AT_return_addr = 0x2a, // block, loclistptr
+ DW_AT_start_scope = 0x2c, // constant
+ DW_AT_bit_stride = 0x2e, // constant
+ DW_AT_upper_bound = 0x2f, // block, constant, reference
+ DW_AT_abstract_origin = 0x31, // reference
+ DW_AT_accessibility = 0x32, // constant
+ DW_AT_address_class = 0x33, // constant
+ DW_AT_artificial = 0x34, // flag
+ DW_AT_base_types = 0x35, // reference
+ DW_AT_calling_convention = 0x36, // constant
+ DW_AT_count = 0x37, // block, constant, reference
+ DW_AT_data_member_location = 0x38, // block, constant, loclistptr
+ DW_AT_decl_column = 0x39, // constant
+ DW_AT_decl_file = 0x3a, // constant
+ DW_AT_decl_line = 0x3b, // constant
+ DW_AT_declaration = 0x3c, // flag
+ DW_AT_discr_list = 0x3d, // block
+ DW_AT_encoding = 0x3e, // constant
+ DW_AT_external = 0x3f, // flag
+ DW_AT_frame_base = 0x40, // block, loclistptr
+ DW_AT_friend = 0x41, // reference
+ DW_AT_identifier_case = 0x42, // constant
+ DW_AT_macro_info = 0x43, // macptr
+ DW_AT_namelist_item = 0x44, // block
+ DW_AT_priority = 0x45, // reference
+ DW_AT_segment = 0x46, // block, loclistptr
+ DW_AT_specification = 0x47, // reference
+ DW_AT_static_link = 0x48, // block, loclistptr
+ DW_AT_type = 0x49, // reference
+ DW_AT_use_location = 0x4a, // block, loclistptr
+ DW_AT_variable_parameter = 0x4b, // flag
+ DW_AT_virtuality = 0x4c, // constant
+ DW_AT_vtable_elem_location = 0x4d, // block, loclistptr
+ // Dwarf3
+ DW_AT_allocated = 0x4e, // block, constant, reference
+ DW_AT_associated = 0x4f, // block, constant, reference
+ DW_AT_data_location = 0x50, // block
+ DW_AT_byte_stride = 0x51, // block, constant, reference
+ DW_AT_entry_pc = 0x52, // address
+ DW_AT_use_UTF8 = 0x53, // flag
+ DW_AT_extension = 0x54, // reference
+ DW_AT_ranges = 0x55, // rangelistptr
+ DW_AT_trampoline = 0x56, // address, flag, reference, string
+ DW_AT_call_column = 0x57, // constant
+ DW_AT_call_file = 0x58, // constant
+ DW_AT_call_line = 0x59, // constant
+ DW_AT_description = 0x5a, // string
+ DW_AT_binary_scale = 0x5b, // constant
+ DW_AT_decimal_scale = 0x5c, // constant
+ DW_AT_small = 0x5d, // reference
+ DW_AT_decimal_sign = 0x5e, // constant
+ DW_AT_digit_count = 0x5f, // constant
+ DW_AT_picture_string = 0x60, // string
+ DW_AT_mutable = 0x61, // flag
+ DW_AT_threads_scaled = 0x62, // flag
+ DW_AT_explicit = 0x63, // flag
+ DW_AT_object_pointer = 0x64, // reference
+ DW_AT_endianity = 0x65, // constant
+ DW_AT_elemental = 0x66, // flag
+ DW_AT_pure = 0x67, // flag
+ DW_AT_recursive = 0x68, // flag
+
+ DW_AT_lo_user = 0x2000, // ---
+ DW_AT_hi_user = 0x3fff, // ---
+
+};
+
+// Table 21
+enum
+{
+ DW_FORM_addr = 0x01, // address
+ DW_FORM_block2 = 0x03, // block
+ DW_FORM_block4 = 0x04, // block
+ DW_FORM_data2 = 0x05, // constant
+ DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_string = 0x08, // string
+ DW_FORM_block = 0x09, // block
+ DW_FORM_block1 = 0x0a, // block
+ DW_FORM_data1 = 0x0b, // constant
+ DW_FORM_flag = 0x0c, // flag
+ DW_FORM_sdata = 0x0d, // constant
+ DW_FORM_strp = 0x0e, // string
+ DW_FORM_udata = 0x0f, // constant
+ DW_FORM_ref_addr = 0x10, // reference
+ DW_FORM_ref1 = 0x11, // reference
+ DW_FORM_ref2 = 0x12, // reference
+ DW_FORM_ref4 = 0x13, // reference
+ DW_FORM_ref8 = 0x14, // reference
+ DW_FORM_ref_udata = 0x15, // reference
+ DW_FORM_indirect = 0x16, // (see Section 7.5.3)
+};
+
+// Table 24 (#operands, notes)
+enum
+{
+ DW_OP_addr = 0x03, // 1 constant address (size target specific)
+ DW_OP_deref = 0x06, // 0
+ DW_OP_const1u = 0x08, // 1 1-byte constant
+ DW_OP_const1s = 0x09, // 1 1-byte constant
+ DW_OP_const2u = 0x0a, // 1 2-byte constant
+ DW_OP_const2s = 0x0b, // 1 2-byte constant
+ DW_OP_const4u = 0x0c, // 1 4-byte constant
+ DW_OP_const4s = 0x0d, // 1 4-byte constant
+ DW_OP_const8u = 0x0e, // 1 8-byte constant
+ DW_OP_const8s = 0x0f, // 1 8-byte constant
+ DW_OP_constu = 0x10, // 1 ULEB128 constant
+ DW_OP_consts = 0x11, // 1 SLEB128 constant
+ DW_OP_dup = 0x12, // 0
+ DW_OP_drop = 0x13, // 0
+ DW_OP_over = 0x14, // 0
+ DW_OP_pick = 0x15, // 1 1-byte stack index
+ DW_OP_swap = 0x16, // 0
+ DW_OP_rot = 0x17, // 0
+ DW_OP_xderef = 0x18, // 0
+ DW_OP_abs = 0x19, // 0
+ DW_OP_and = 0x1a, // 0
+ DW_OP_div = 0x1b, // 0
+ DW_OP_minus = 0x1c, // 0
+ DW_OP_mod = 0x1d, // 0
+ DW_OP_mul = 0x1e, // 0
+ DW_OP_neg = 0x1f, // 0
+ DW_OP_not = 0x20, // 0
+ DW_OP_or = 0x21, // 0
+ DW_OP_plus = 0x22, // 0
+ DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend
+ DW_OP_shl = 0x24, // 0
+ DW_OP_shr = 0x25, // 0
+ DW_OP_shra = 0x26, // 0
+ DW_OP_xor = 0x27, // 0
+ DW_OP_skip = 0x2f, // 1 signed 2-byte constant
+ DW_OP_bra = 0x28, // 1 signed 2-byte constant
+ DW_OP_eq = 0x29, // 0
+ DW_OP_ge = 0x2a, // 0
+ DW_OP_gt = 0x2b, // 0
+ DW_OP_le = 0x2c, // 0
+ DW_OP_lt = 0x2d, // 0
+ DW_OP_ne = 0x2e, // 0
+ DW_OP_lit0 = 0x30, // 0 ...
+ DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 +
+ // literal)
+ DW_OP_reg0 = 0x50, // 0 ..
+ DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum)
+ DW_OP_breg0 = 0x70, // 1 ...
+ DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
+ DW_OP_regx = 0x90, // 1 ULEB128 register
+ DW_OP_fbreg = 0x91, // 1 SLEB128 offset
+ DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved
+ DW_OP_nop = 0x96, // 0
+ DW_OP_push_object_address = 0x97, // 0
+ DW_OP_call2 = 0x98, // 1 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 1 4-byte offset of DIE
+ DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE
+ DW_OP_form_tls_address = 0x9b, // 0
+ DW_OP_call_frame_cfa = 0x9c, // 0
+ DW_OP_bit_piece = 0x9d, // 2
+ DW_OP_lo_user = 0xe0,
+ DW_OP_hi_user = 0xff,
+};
+
+// Table 25
+enum
+{
+ DW_ATE_address = 0x01,
+ DW_ATE_boolean = 0x02,
+ DW_ATE_complex_float = 0x03,
+ DW_ATE_float = 0x04,
+ DW_ATE_signed = 0x05,
+ DW_ATE_signed_char = 0x06,
+ DW_ATE_unsigned = 0x07,
+ DW_ATE_unsigned_char = 0x08,
+ DW_ATE_imaginary_float = 0x09,
+ DW_ATE_packed_decimal = 0x0a,
+ DW_ATE_numeric_string = 0x0b,
+ DW_ATE_edited = 0x0c,
+ DW_ATE_signed_fixed = 0x0d,
+ DW_ATE_unsigned_fixed = 0x0e,
+ DW_ATE_decimal_float = 0x0f,
+ DW_ATE_lo_user = 0x80,
+ DW_ATE_hi_user = 0xff,
+};
+
+// Table 26
+enum
+{
+ DW_DS_unsigned = 0x01,
+ DW_DS_leading_overpunch = 0x02,
+ DW_DS_trailing_overpunch = 0x03,
+ DW_DS_leading_separate = 0x04,
+ DW_DS_trailing_separate = 0x05,
+};
+
+// Table 27
+enum
+{
+ DW_END_default = 0x00,
+ DW_END_big = 0x01,
+ DW_END_little = 0x02,
+ DW_END_lo_user = 0x40,
+ DW_END_hi_user = 0xff,
+};
+
+// Table 28
+enum
+{
+ DW_ACCESS_public = 0x01,
+ DW_ACCESS_protected = 0x02,
+ DW_ACCESS_private = 0x03,
+};
+
+// Table 29
+enum
+{
+ DW_VIS_local = 0x01,
+ DW_VIS_exported = 0x02,
+ DW_VIS_qualified = 0x03,
+};
+
+// Table 30
+enum
+{
+ DW_VIRTUALITY_none = 0x00,
+ DW_VIRTUALITY_virtual = 0x01,
+ DW_VIRTUALITY_pure_virtual = 0x02,
+};
+
+// Table 31
+enum
+{
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ // Dwarf3
+ DW_LANG_Java = 0x000b,
+ DW_LANG_C99 = 0x000c,
+ DW_LANG_Ada95 = 0x000d,
+ DW_LANG_Fortran95 = 0x000e,
+ DW_LANG_PLI = 0x000f,
+ DW_LANG_ObjC = 0x0010,
+ DW_LANG_ObjC_plus_plus = 0x0011,
+ DW_LANG_UPC = 0x0012,
+ DW_LANG_D = 0x0013,
+ // Dwarf4
+ DW_LANG_Python = 0x0014,
+ // Dwarf5
+ DW_LANG_Go = 0x0016,
+
+ DW_LANG_lo_user = 0x8000,
+ DW_LANG_hi_user = 0xffff,
+};
+
+// Table 32
+enum
+{
+ DW_ID_case_sensitive = 0x00,
+ DW_ID_up_case = 0x01,
+ DW_ID_down_case = 0x02,
+ DW_ID_case_insensitive = 0x03,
+};
+
+// Table 33
+enum
+{
+ DW_CC_normal = 0x01,
+ DW_CC_program = 0x02,
+ DW_CC_nocall = 0x03,
+ DW_CC_lo_user = 0x40,
+ DW_CC_hi_user = 0xff,
+};
+
+// Table 34
+enum
+{
+ DW_INL_not_inlined = 0x00,
+ DW_INL_inlined = 0x01,
+ DW_INL_declared_not_inlined = 0x02,
+ DW_INL_declared_inlined = 0x03,
+};
+
+// Table 35
+enum
+{
+ DW_ORD_row_major = 0x00,
+ DW_ORD_col_major = 0x01,
+};
+
+// Table 36
+enum
+{
+ DW_DSC_label = 0x00,
+ DW_DSC_range = 0x01,
+};
+
+// Table 37
+enum
+{
+ DW_LNS_copy = 0x01,
+ DW_LNS_advance_pc = 0x02,
+ DW_LNS_advance_line = 0x03,
+ DW_LNS_set_file = 0x04,
+ DW_LNS_set_column = 0x05,
+ DW_LNS_negate_stmt = 0x06,
+ DW_LNS_set_basic_block = 0x07,
+ DW_LNS_const_add_pc = 0x08,
+ DW_LNS_fixed_advance_pc = 0x09,
+ // Dwarf3
+ DW_LNS_set_prologue_end = 0x0a,
+ DW_LNS_set_epilogue_begin = 0x0b,
+ DW_LNS_set_isa = 0x0c,
+};
+
+// Table 38
+enum
+{
+ DW_LNE_end_sequence = 0x01,
+ DW_LNE_set_address = 0x02,
+ DW_LNE_define_file = 0x03,
+ DW_LNE_lo_user = 0x80,
+ DW_LNE_hi_user = 0xff,
+};
+
+// Table 39
+enum
+{
+ DW_MACINFO_define = 0x01,
+ DW_MACINFO_undef = 0x02,
+ DW_MACINFO_start_file = 0x03,
+ DW_MACINFO_end_file = 0x04,
+ DW_MACINFO_vendor_ext = 0xff,
+};
+
+// Table 40.
+enum
+{ // operand,...
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01, // address
+ DW_CFA_advance_loc1 = 0x02, // 1-byte delta
+ DW_CFA_advance_loc2 = 0x03, // 2-byte delta
+ DW_CFA_advance_loc4 = 0x04, // 4-byte delta
+ DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset
+ DW_CFA_restore_extended = 0x06, // ULEB128 register
+ DW_CFA_undefined = 0x07, // ULEB128 register
+ DW_CFA_same_value = 0x08, // ULEB128 register
+ DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset
+ DW_CFA_def_cfa_register = 0x0d, // ULEB128 register
+ DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset
+ DW_CFA_def_cfa_expression = 0x0f, // BLOCK
+ DW_CFA_expression = 0x10, // ULEB128 register, BLOCK
+ DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset
+ DW_CFA_val_offset = 0x14, // ULEB128, ULEB128
+ DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128
+ DW_CFA_val_expression = 0x16, // ULEB128, BLOCK
+
+ DW_CFA_lo_user = 0x1c,
+ DW_CFA_hi_user = 0x3f,
+
+ // Opcodes that take an addend operand.
+ DW_CFA_advance_loc = 0x1<<6, // +delta
+ DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset)
+ DW_CFA_restore = 0x3<<6, // +register
+};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index c5d58576d..d5b0b0311 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -21,6 +21,16 @@ static ElfPhdr *phdr[NSECT];
static ElfShdr *shdr[NSECT];
static char *interp;
+typedef struct Elfstring Elfstring;
+struct Elfstring
+{
+ char *s;
+ int off;
+};
+
+static Elfstring elfstr[100];
+static int nelfstr;
+
/*
Initialize the global variable that describes the ELF header. It will be updated as
we write section and prog headers.
@@ -122,6 +132,18 @@ elfwriteshdrs(void)
return hdr.shnum * ELF32SHDRSIZE;
}
+void
+elfsetstring(char *s, int off)
+{
+ if(nelfstr >= nelem(elfstr)) {
+ diag("too many elf strings");
+ errorexit();
+ }
+ elfstr[nelfstr].s = s;
+ elfstr[nelfstr].off = off;
+ nelfstr++;
+}
+
uint32
elfwritephdrs(void)
{
@@ -142,8 +164,7 @@ newElfPhdr(void)
{
ElfPhdr *e;
- e = malloc(sizeof *e);
- memset(e, 0, sizeof *e);
+ e = mal(sizeof *e);
if (hdr.phnum >= NSECT)
diag("too many phdrs");
else
@@ -167,8 +188,7 @@ newElfShdr(vlong name)
{
ElfShdr *e;
- e = malloc(sizeof *e);
- memset(e, 0, sizeof *e);
+ e = mal(sizeof *e);
e->name = name;
if (hdr.shnum >= NSECT) {
diag("too many shdrs");
@@ -294,7 +314,7 @@ elfwriteinterp(void)
n = strlen(interp)+1;
seek(cout, ELFRESERVE-n, 0);
- write(cout, interp, n);
+ ewrite(cout, interp, n);
return n;
}
@@ -310,17 +330,25 @@ elfinterp(ElfShdr *sh, uint64 startva, char *p)
sh->size = n;
}
+extern int nelfsym;
+
void
-elfdynhash(int nsym)
+elfdynhash(void)
{
Sym *s, *sy;
int i, h, nbucket, b;
uchar *pc;
uint32 hc, g;
uint32 *chain, *buckets;
+ int nsym;
+ char *name;
+
+ if(!iself)
+ return;
+ nsym = nelfsym;
s = lookup(".hash", 0);
- s->type = SELFDATA; // TODO: rodata
+ s->type = SELFDATA;
s->reachable = 1;
i = nsym;
@@ -331,17 +359,24 @@ elfdynhash(int nsym)
}
chain = malloc(nsym * sizeof(uint32));
- memset(chain, 0, nsym * sizeof(uint32));
buckets = malloc(nbucket * sizeof(uint32));
+ if(chain == nil || buckets == nil) {
+ cursym = nil;
+ diag("out of memory");
+ errorexit();
+ }
+ memset(chain, 0, nsym * sizeof(uint32));
memset(buckets, 0, nbucket * sizeof(uint32));
- i = 1;
for(h = 0; h<NHASH; h++) {
- for(sy=hash[h]; sy!=S; sy=sy->link) {
- if (!sy->reachable || (sy->type != STEXT && sy->type != SDATA && sy->type != SBSS) || sy->dynimpname == nil)
+ for(sy=hash[h]; sy!=S; sy=sy->hash) {
+ if (sy->dynid <= 0)
continue;
hc = 0;
- for(pc = (uchar*)sy->dynimpname; *pc; pc++) {
+ name = sy->dynimpname;
+ if(name == nil)
+ name = sy->name;
+ for(pc = (uchar*)name; *pc; pc++) {
hc = (hc<<4) + *pc;
g = hc & 0xf0000000;
hc ^= g >> 24;
@@ -349,9 +384,8 @@ elfdynhash(int nsym)
}
b = hc % nbucket;
- chain[i] = buckets[b];
- buckets[b] = i;
- i++;
+ chain[sy->dynid] = buckets[b];
+ buckets[b] = sy->dynid;
}
}
@@ -364,4 +398,64 @@ elfdynhash(int nsym)
free(chain);
free(buckets);
+
+ elfwritedynent(lookup(".dynamic", 0), DT_NULL, 0);
+}
+
+ElfPhdr*
+elfphload(Segment *seg)
+{
+ ElfPhdr *ph;
+
+ ph = newElfPhdr();
+ ph->type = PT_LOAD;
+ if(seg->rwx & 4)
+ ph->flags |= PF_R;
+ if(seg->rwx & 2)
+ ph->flags |= PF_W;
+ if(seg->rwx & 1)
+ ph->flags |= PF_X;
+ ph->vaddr = seg->vaddr;
+ ph->paddr = seg->vaddr;
+ ph->memsz = seg->len;
+ ph->off = seg->fileoff;
+ ph->filesz = seg->filelen;
+ ph->align = INITRND;
+
+ return ph;
+}
+
+ElfShdr*
+elfshbits(Section *sect)
+{
+ int i, off;
+ ElfShdr *sh;
+
+ for(i=0; i<nelfstr; i++) {
+ if(strcmp(sect->name, elfstr[i].s) == 0) {
+ off = elfstr[i].off;
+ goto found;
+ }
+ }
+ diag("cannot find elf name %s", sect->name);
+ errorexit();
+ return nil;
+
+found:
+ sh = newElfShdr(off);
+ if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
+ sh->type = SHT_PROGBITS;
+ else
+ sh->type = SHT_NOBITS;
+ sh->flags = SHF_ALLOC;
+ if(sect->rwx & 1)
+ sh->flags |= SHF_EXECINSTR;
+ if(sect->rwx & 2)
+ sh->flags |= SHF_WRITE;
+ sh->addr = sect->vaddr;
+ sh->addralign = PtrSize;
+ sh->size = sect->len;
+ sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+
+ return sh;
}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 9b5fdb17e..df15cb115 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -964,7 +964,10 @@ extern int numelfshdr;
extern int iself;
int elfwriteinterp(void);
void elfinterp(ElfShdr*, uint64, char*);
-void elfdynhash(int);
+void elfdynhash(void);
+ElfPhdr* elfphload(Segment*);
+ElfShdr* elfshbits(Section*);
+void elfsetstring(char*, int);
/*
* Total amount of space to reserve at the start of the file
@@ -972,5 +975,4 @@ void elfdynhash(int);
* May waste some.
* On FreeBSD, cannot be larger than a page.
*/
-#define ELFRESERVE 2048
-
+#define ELFRESERVE 3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 015f34db2..8966b2a1f 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -66,12 +66,11 @@ ilookup(char *name)
}
static void loadpkgdata(char*, char*, char*, int);
-static void loaddynimport(char*, char*, int);
+static void loaddynimport(char*, char*, char*, int);
static void loaddynexport(char*, char*, char*, int);
static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-static int ndynexp;
static Sym **dynexp;
void
@@ -194,7 +193,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
errorexit();
return;
}
- loaddynimport(filename, p0 + 1, p1 - (p0+1));
+ loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1));
}
// look for dynexp section
@@ -266,6 +265,10 @@ expandpkg(char *t0, char *pkg)
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
+ if(w0 == nil) {
+ diag("out of memory");
+ errorexit();
+ }
w = w0;
for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
memmove(w, t, p - t);
@@ -282,7 +285,7 @@ static int
parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
char *p, *prefix, *name, *def, *edef, *meth;
- int n;
+ int n, inquote;
// skip white space
p = *pp;
@@ -319,8 +322,19 @@ loop:
// name: a.b followed by space
name = p;
- while(p < ep && *p != ' ')
+ inquote = 0;
+ while(p < ep) {
+ if (*p == ' ' && !inquote)
+ break;
+
+ if(*p == '\\')
+ p++;
+ else if(*p == '"')
+ inquote = !inquote;
+
p++;
+ }
+
if(p >= ep)
return -1;
*p++ = '\0';
@@ -397,7 +411,7 @@ parsemethod(char **pp, char *ep, char **methp)
}
static void
-loaddynimport(char *file, char *p, int n)
+loaddynimport(char *file, char *pkg, char *p, int n)
{
char *pend, *next, *name, *def, *p0, *lib;
Sym *s;
@@ -431,10 +445,21 @@ loaddynimport(char *file, char *p, int n)
// successful parse: now can edit the line
*strchr(name, ' ') = 0;
*strchr(def, ' ') = 0;
+
+ if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) {
+ // allow #pragma dynimport _ _ "foo.so"
+ // to force a link of foo.so.
+ adddynlib(lib);
+ continue;
+ }
+ name = expandpkg(name, pkg);
s = lookup(name, 0);
- s->dynimplib = lib;
- s->dynimpname = def;
+ if(s->type == 0 || s->type == SXREF) {
+ s->dynimplib = lib;
+ s->dynimpname = def;
+ s->type = SDYNIMPORT;
+ }
}
return;
@@ -499,38 +524,19 @@ err:
static int markdepth;
static void
-markdata(Prog *p, Sym *s)
-{
- markdepth++;
- if(p != P && debug['v'] > 1)
- Bprint(&bso, "%d markdata %s\n", markdepth, s->name);
- for(; p != P; p=p->dlink)
- if(p->to.sym)
- mark(p->to.sym);
- markdepth--;
-}
-
-static void
-marktext(Prog *p)
+marktext(Sym *s)
{
Auto *a;
+ Prog *p;
- if(p == P)
+ if(s == S)
return;
- if(p->as != ATEXT) {
- diag("marktext: %P", p);
- return;
- }
- for(a=p->to.autom; a; a=a->link)
- mark(a->gotype);
markdepth++;
if(debug['v'] > 1)
- Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name);
- for(a=p->to.autom; a; a=a->link)
+ Bprint(&bso, "%d marktext %s\n", markdepth, s->name);
+ for(a=s->autom; a; a=a->link)
mark(a->gotype);
- for(p=p->link; p != P; p=p->link) {
- if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL)
- break;
+ for(p=s->text; p != P; p=p->link) {
if(p->from.sym)
mark(p->from.sym);
if(p->to.sym)
@@ -542,45 +548,21 @@ marktext(Prog *p)
void
mark(Sym *s)
{
+ int i;
+
if(s == S || s->reachable)
return;
s->reachable = 1;
if(s->text)
- marktext(s->text);
- if(s->data)
- markdata(s->data, s);
+ marktext(s);
+ for(i=0; i<s->nr; i++)
+ mark(s->r[i].sym);
if(s->gotype)
mark(s->gotype);
-}
-
-static void
-sweeplist(Prog **first, Prog **last)
-{
- int reachable;
- Prog *p, *q;
-
- reachable = 1;
- q = P;
- for(p=*first; p != P; p=p->link) {
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- reachable = p->from.sym->reachable;
- }
- if(reachable) {
- if(q == P)
- *first = p;
- else
- q->link = p;
- q = p;
- }
- }
- if(q == P)
- *first = P;
- else
- q->link = P;
- *last = q;
+ if(s->sub)
+ mark(s->sub);
+ if(s->outer)
+ mark(s->outer);
}
static char*
@@ -602,10 +584,43 @@ morename[] =
"runtime.morestack48",
};
+static int
+isz(Auto *a)
+{
+ for(; a; a=a->link)
+ if(a->type == D_FILE || a->type == D_FILE1)
+ return 1;
+ return 0;
+}
+
+static void
+addz(Sym *s, Auto *z)
+{
+ Auto *a, *last;
+
+ // strip out non-z
+ last = nil;
+ for(a = z; a != nil; a = a->link) {
+ if(a->type == D_FILE || a->type == D_FILE1) {
+ if(last == nil)
+ z = a;
+ else
+ last->link = a;
+ last = a;
+ }
+ }
+ if(last) {
+ last->link = s->autom;
+ s->autom = z;
+ }
+}
+
void
deadcode(void)
{
int i;
+ Sym *s, *last;
+ Auto *z;
if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime());
@@ -616,7 +631,38 @@ deadcode(void)
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
+
+ // remove dead text but keep file information (z symbols).
+ last = nil;
+ z = nil;
+ for(s = textp; s != nil; s = s->next) {
+ if(!s->reachable) {
+ if(isz(s->autom))
+ z = s->autom;
+ continue;
+ }
+ if(last == nil)
+ textp = s;
+ else
+ last->next = s;
+ last = s;
+ if(z != nil) {
+ if(!isz(s->autom))
+ addz(s, z);
+ z = nil;
+ }
+ }
+ if(last == nil)
+ textp = nil;
+ else
+ last->next = nil;
+}
- // remove dead data
- sweeplist(&datap, &edatap);
+void
+addexport(void)
+{
+ int i;
+
+ for(i=0; i<ndynexp; i++)
+ adddynsym(dynexp[i]);
}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
new file mode 100644
index 000000000..44bbe68ee
--- /dev/null
+++ b/src/cmd/ld/ldelf.c
@@ -0,0 +1,816 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+ Copyright © 2004 Russ Cox.
+ Portions Copyright © 2008-2010 Google Inc.
+ Portions Copyright © 2010 The Go Authors.
+
+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 "l.h"
+#include "lib.h"
+#include "../ld/elf.h"
+
+enum
+{
+ ElfClassNone = 0,
+ ElfClass32,
+ ElfClass64,
+
+ ElfDataNone = 0,
+ ElfDataLsb,
+ ElfDataMsb,
+
+ ElfTypeNone = 0,
+ ElfTypeRelocatable,
+ ElfTypeExecutable,
+ ElfTypeSharedObject,
+ ElfTypeCore,
+ /* 0xFF00 - 0xFFFF reserved for processor-specific types */
+
+ ElfMachNone = 0,
+ ElfMach32100, /* AT&T WE 32100 */
+ ElfMachSparc, /* SPARC */
+ ElfMach386, /* Intel 80386 */
+ ElfMach68000, /* Motorola 68000 */
+ ElfMach88000, /* Motorola 88000 */
+ ElfMach486, /* Intel 80486, no longer used */
+ ElfMach860, /* Intel 80860 */
+ ElfMachMips, /* MIPS RS3000 */
+ ElfMachS370, /* IBM System/370 */
+ ElfMachMipsLe, /* MIPS RS3000 LE */
+ ElfMachParisc = 15, /* HP PA RISC */
+ ElfMachVpp500 = 17, /* Fujitsu VPP500 */
+ ElfMachSparc32Plus, /* SPARC V8+ */
+ ElfMach960, /* Intel 80960 */
+ ElfMachPower, /* PowerPC */
+ ElfMachPower64, /* PowerPC 64 */
+ ElfMachS390, /* IBM System/390 */
+ ElfMachV800 = 36, /* NEC V800 */
+ ElfMachFr20, /* Fujitsu FR20 */
+ ElfMachRh32, /* TRW RH-32 */
+ ElfMachRce, /* Motorola RCE */
+ ElfMachArm, /* ARM */
+ ElfMachAlpha, /* Digital Alpha */
+ ElfMachSH, /* Hitachi SH */
+ ElfMachSparc9, /* SPARC V9 */
+ ElfMachAmd64 = 62,
+ /* and the list goes on... */
+
+ ElfAbiNone = 0,
+ ElfAbiSystemV = 0, /* [sic] */
+ ElfAbiHPUX,
+ ElfAbiNetBSD,
+ ElfAbiLinux,
+ ElfAbiSolaris = 6,
+ ElfAbiAix,
+ ElfAbiIrix,
+ ElfAbiFreeBSD,
+ ElfAbiTru64,
+ ElfAbiModesto,
+ ElfAbiOpenBSD,
+ ElfAbiARM = 97,
+ ElfAbiEmbedded = 255,
+
+ /* some of sections 0xFF00 - 0xFFFF reserved for various things */
+ ElfSectNone = 0,
+ ElfSectProgbits,
+ ElfSectSymtab,
+ ElfSectStrtab,
+ ElfSectRela,
+ ElfSectHash,
+ ElfSectDynamic,
+ ElfSectNote,
+ ElfSectNobits,
+ ElfSectRel,
+ ElfSectShlib,
+ ElfSectDynsym,
+
+ ElfSectFlagWrite = 0x1,
+ ElfSectFlagAlloc = 0x2,
+ ElfSectFlagExec = 0x4,
+ /* 0xF0000000 are reserved for processor specific */
+
+ ElfSymBindLocal = 0,
+ ElfSymBindGlobal,
+ ElfSymBindWeak,
+ /* 13-15 reserved */
+
+ ElfSymTypeNone = 0,
+ ElfSymTypeObject,
+ ElfSymTypeFunc,
+ ElfSymTypeSection,
+ ElfSymTypeFile,
+ /* 13-15 reserved */
+
+ ElfSymShnNone = 0,
+ ElfSymShnAbs = 0xFFF1,
+ ElfSymShnCommon = 0xFFF2,
+ /* 0xFF00-0xFF1F reserved for processors */
+ /* 0xFF20-0xFF3F reserved for operating systems */
+
+ ElfProgNone = 0,
+ ElfProgLoad,
+ ElfProgDynamic,
+ ElfProgInterp,
+ ElfProgNote,
+ ElfProgShlib,
+ ElfProgPhdr,
+
+ ElfProgFlagExec = 0x1,
+ ElfProgFlagWrite = 0x2,
+ ElfProgFlagRead = 0x4,
+
+ ElfNotePrStatus = 1,
+ ElfNotePrFpreg = 2,
+ ElfNotePrPsinfo = 3,
+ ElfNotePrTaskstruct = 4,
+ ElfNotePrAuxv = 6,
+ ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */
+};
+
+typedef struct ElfHdrBytes ElfHdrBytes;
+typedef struct ElfSectBytes ElfSectBytes;
+typedef struct ElfProgBytes ElfProgBytes;
+typedef struct ElfSymBytes ElfSymBytes;
+
+typedef struct ElfHdrBytes64 ElfHdrBytes64;
+typedef struct ElfSectBytes64 ElfSectBytes64;
+typedef struct ElfProgBytes64 ElfProgBytes64;
+typedef struct ElfSymBytes64 ElfSymBytes64;
+
+struct ElfHdrBytes
+{
+ uchar ident[16];
+ uchar type[2];
+ uchar machine[2];
+ uchar version[4];
+ uchar entry[4];
+ uchar phoff[4];
+ uchar shoff[4];
+ uchar flags[4];
+ uchar ehsize[2];
+ uchar phentsize[2];
+ uchar phnum[2];
+ uchar shentsize[2];
+ uchar shnum[2];
+ uchar shstrndx[2];
+};
+
+struct ElfHdrBytes64
+{
+ uchar ident[16];
+ uchar type[2];
+ uchar machine[2];
+ uchar version[4];
+ uchar entry[8];
+ uchar phoff[8];
+ uchar shoff[8];
+ uchar flags[4];
+ uchar ehsize[2];
+ uchar phentsize[2];
+ uchar phnum[2];
+ uchar shentsize[2];
+ uchar shnum[2];
+ uchar shstrndx[2];
+};
+
+struct ElfSectBytes
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[4];
+ uchar addr[4];
+ uchar off[4];
+ uchar size[4];
+ uchar link[4];
+ uchar info[4];
+ uchar align[4];
+ uchar entsize[4];
+};
+
+struct ElfSectBytes64
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[8];
+ uchar addr[8];
+ uchar off[8];
+ uchar size[8];
+ uchar link[4];
+ uchar info[4];
+ uchar align[8];
+ uchar entsize[8];
+};
+
+struct ElfSymBytes
+{
+ uchar name[4];
+ uchar value[4];
+ uchar size[4];
+ uchar info; /* top4: bind, bottom4: type */
+ uchar other;
+ uchar shndx[2];
+};
+
+struct ElfSymBytes64
+{
+ uchar name[4];
+ uchar info; /* top4: bind, bottom4: type */
+ uchar other;
+ uchar shndx[2];
+ uchar value[8];
+ uchar size[8];
+};
+
+typedef struct ElfSect ElfSect;
+typedef struct ElfObj ElfObj;
+typedef struct ElfSym ElfSym;
+
+struct ElfSect
+{
+ char *name;
+ uint32 type;
+ uint64 flags;
+ uint64 addr;
+ uint64 off;
+ uint64 size;
+ uint32 link;
+ uint32 info;
+ uint64 align;
+ uint64 entsize;
+ uchar *base;
+ Sym *sym;
+};
+
+struct ElfObj
+{
+ Biobuf *f;
+ int64 base; // offset in f where ELF begins
+ int64 len; // length of ELF
+ int is64;
+ char *name;
+
+ Endian *e;
+ ElfSect *sect;
+ uint nsect;
+ char *shstrtab;
+ int nsymtab;
+ ElfSect *symtab;
+ ElfSect *symstr;
+
+ uint32 type;
+ uint32 machine;
+ uint32 version;
+ uint64 entry;
+ uint64 phoff;
+ uint64 shoff;
+ uint32 flags;
+ uint32 ehsize;
+ uint32 phentsize;
+ uint32 phnum;
+ uint32 shentsize;
+ uint32 shnum;
+ uint32 shstrndx;
+};
+
+struct ElfSym
+{
+ char* name;
+ uint64 value;
+ uint64 size;
+ uchar bind;
+ uchar type;
+ uchar other;
+ uint16 shndx;
+ Sym* sym;
+};
+
+uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
+
+static ElfSect* section(ElfObj*, char*);
+static int map(ElfObj*, ElfSect*);
+static int readsym(ElfObj*, int i, ElfSym*);
+static int reltype(char*, int, uchar*);
+
+void
+ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 base;
+ uint64 add, info;
+ char *name;
+ int i, j, rela, is64, n;
+ uchar hdrbuf[64];
+ uchar *p, *dp;
+ ElfHdrBytes *hdr;
+ ElfObj *obj;
+ ElfSect *sect, *rsect;
+ ElfSym sym;
+ Endian *e;
+ Reloc *r, *rp;
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
+
+ version++;
+ base = Boffset(f);
+
+ if(Bread(f, &hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
+ goto bad;
+ hdr = (ElfHdrBytes*)&hdrbuf;
+ if(memcmp(hdr->ident, ElfMagic, 4) != 0)
+ goto bad;
+ switch(hdr->ident[5]) {
+ case ElfDataLsb:
+ e = &le;
+ break;
+ case ElfDataMsb:
+ e = &be;
+ break;
+ default:
+ goto bad;
+ }
+
+ // read header
+ obj = mal(sizeof *obj);
+ obj->e = e;
+ obj->f = f;
+ obj->base = base;
+ obj->len = len;
+ obj->name = pn;
+
+ is64 = 0;
+ if(hdr->ident[4] == ElfClass64) {
+ ElfHdrBytes64* hdr;
+
+ is64 = 1;
+ hdr = (ElfHdrBytes64*)hdrbuf;
+ obj->type = e->e16(hdr->type);
+ obj->machine = e->e16(hdr->machine);
+ obj->version = e->e32(hdr->version);
+ obj->phoff = e->e64(hdr->phoff);
+ obj->shoff = e->e64(hdr->shoff);
+ obj->flags = e->e32(hdr->flags);
+ obj->ehsize = e->e16(hdr->ehsize);
+ obj->phentsize = e->e16(hdr->phentsize);
+ obj->phnum = e->e16(hdr->phnum);
+ obj->shentsize = e->e16(hdr->shentsize);
+ obj->shnum = e->e16(hdr->shnum);
+ obj->shstrndx = e->e16(hdr->shstrndx);
+ } else {
+ obj->type = e->e16(hdr->type);
+ obj->machine = e->e16(hdr->machine);
+ obj->version = e->e32(hdr->version);
+ obj->entry = e->e32(hdr->entry);
+ obj->phoff = e->e32(hdr->phoff);
+ obj->shoff = e->e32(hdr->shoff);
+ obj->flags = e->e32(hdr->flags);
+ obj->ehsize = e->e16(hdr->ehsize);
+ obj->phentsize = e->e16(hdr->phentsize);
+ obj->phnum = e->e16(hdr->phnum);
+ obj->shentsize = e->e16(hdr->shentsize);
+ obj->shnum = e->e16(hdr->shnum);
+ obj->shstrndx = e->e16(hdr->shstrndx);
+ }
+ obj->is64 = is64;
+
+ if(hdr->ident[6] != obj->version)
+ goto bad;
+
+ if(e->e16(hdr->type) != ElfTypeRelocatable) {
+ diag("%s: elf but not elf relocatable object");
+ return;
+ }
+
+ switch(thechar) {
+ default:
+ diag("%s: elf %s unimplemented", thestring);
+ return;
+ case '5':
+ if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
+ diag("%s: elf object but not arm", pn);
+ return;
+ }
+ break;
+ case '6':
+ if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
+ diag("%s: elf object but not amd64", pn);
+ return;
+ }
+ break;
+ case '8':
+ if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
+ diag("%s: elf object but not 386", pn);
+ return;
+ }
+ break;
+ }
+
+ // load section list into memory.
+ obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
+ obj->nsect = obj->shnum;
+ for(i=0; i<obj->nsect; i++) {
+ if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
+ goto bad;
+ sect = &obj->sect[i];
+ if(is64) {
+ ElfSectBytes64 b;
+
+ werrstr("short read");
+ if(Bread(f, &b, sizeof b) != sizeof b)
+ goto bad;
+
+ sect->name = (char*)(uintptr)e->e32(b.name);
+ sect->type = e->e32(b.type);
+ sect->flags = e->e64(b.flags);
+ sect->addr = e->e64(b.addr);
+ sect->off = e->e64(b.off);
+ sect->size = e->e64(b.size);
+ sect->link = e->e32(b.link);
+ sect->info = e->e32(b.info);
+ sect->align = e->e64(b.align);
+ sect->entsize = e->e64(b.entsize);
+ } else {
+ ElfSectBytes b;
+
+ werrstr("short read");
+ if(Bread(f, &b, sizeof b) != sizeof b)
+ goto bad;
+
+ sect->name = (char*)(uintptr)e->e32(b.name);
+ sect->type = e->e32(b.type);
+ sect->flags = e->e32(b.flags);
+ sect->addr = e->e32(b.addr);
+ sect->off = e->e32(b.off);
+ sect->size = e->e32(b.size);
+ sect->link = e->e32(b.link);
+ sect->info = e->e32(b.info);
+ sect->align = e->e32(b.align);
+ sect->entsize = e->e32(b.entsize);
+ }
+ }
+
+ // read section string table and translate names
+ if(obj->shstrndx >= obj->nsect) {
+ werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
+ goto bad;
+ }
+ sect = &obj->sect[obj->shstrndx];
+ if(map(obj, sect) < 0)
+ goto bad;
+ for(i=0; i<obj->nsect; i++)
+ if(obj->sect[i].name != nil)
+ obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
+
+ // load string table for symbols into memory.
+ obj->symtab = section(obj, ".symtab");
+ if(obj->symtab == nil) {
+ // our work is done here - no symbols means nothing can refer to this file
+ return;
+ }
+ if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
+ diag("%s: elf object has symbol table with invalid string table link", pn);
+ return;
+ }
+ obj->symstr = &obj->sect[obj->symtab->link];
+ if(is64)
+ obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
+ else
+ obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
+
+ if(map(obj, obj->symtab) < 0)
+ goto bad;
+ if(map(obj, obj->symstr) < 0)
+ goto bad;
+
+ // load text and data segments into memory.
+ // they are not as small as the section lists, but we'll need
+ // the memory anyway for the symbol images, so we might
+ // as well use one large chunk.
+
+ // create symbols for mapped sections
+ for(i=0; i<obj->nsect; i++) {
+ sect = &obj->sect[i];
+ if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
+ continue;
+ if(sect->type != ElfSectNobits && map(obj, sect) < 0)
+ goto bad;
+
+ name = smprint("%s(%s)", pn, sect->name);
+ s = lookup(name, version);
+ free(name);
+ switch(sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
+ default:
+ werrstr("unexpected flags for ELF section %s", sect->name);
+ goto bad;
+ case ElfSectFlagAlloc:
+ s->type = SRODATA;
+ break;
+ case ElfSectFlagAlloc + ElfSectFlagWrite:
+ s->type = SDATA;
+ break;
+ case ElfSectFlagAlloc + ElfSectFlagExec:
+ s->type = STEXT;
+ break;
+ }
+ if(sect->type == ElfSectProgbits) {
+ 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->type != ElfSectRela && rsect->type != ElfSectRel)
+ continue;
+ if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
+ continue;
+ sect = &obj->sect[rsect->info];
+ if(map(obj, rsect) < 0)
+ goto bad;
+ rela = rsect->type == ElfSectRela;
+ n = rsect->size/(4+4*is64)/(2+rela);
+ r = mal(n*sizeof r[0]);
+ p = rsect->base;
+ dp = sect->base;
+ for(j=0; j<n; j++) {
+ add = 0;
+ rp = &r[j];
+ if(is64) {
+ // 64-bit rel/rela
+ rp->off = e->e64(p);
+ p += 8;
+ info = e->e64(p);
+ p += 8;
+ if(rela) {
+ add = e->e64(p);
+ p += 8;
+ }
+ } else {
+ // 32-bit rel/rela
+ rp->off = e->e32(p);
+ p += 4;
+ info = e->e32(p);
+ info = info>>8<<32 | (info&0xff); // convert to 64-bit info
+ p += 4;
+ if(rela) {
+ add = e->e32(p);
+ p += 4;
+ }
+ }
+ if(readsym(obj, info>>32, &sym) < 0)
+ goto bad;
+ if(sym.sym == nil) {
+ werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
+ sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
+ goto bad;
+ }
+ rp->sym = sym.sym;
+ rp->type = reltype(pn, (uint32)info, &rp->siz);
+ if(rela)
+ rp->add = add;
+ else {
+ // load addend from image
+ if(rp->siz == 4)
+ rp->add = e->e32(sect->base+rp->off);
+ else if(rp->siz == 8)
+ rp->add = e->e64(sect->base+rp->off);
+ else
+ diag("invalid rela size %d", rp->siz);
+ }
+ }
+ qsort(r, n, sizeof r[0], rbyoff); // just in case
+
+ s = sect->sym;
+ s->r = r;
+ s->nr = n;
+ }
+
+ // enter sub-symbols into symbol table.
+ // symbol 0 is the null symbol.
+ for(i=1; i<obj->nsymtab; i++) {
+ if(readsym(obj, i, &sym) < 0)
+ goto bad;
+ if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
+ continue;
+ if(sym.shndx == ElfSymShnCommon) {
+ s = sym.sym;
+ if(s->size < sym.size)
+ s->size = sym.size;
+ if(s->type == 0 || s->type == SXREF)
+ s->type = SBSS;
+ continue;
+ }
+ if(sym.shndx >= obj->nsect || sym.shndx == 0)
+ continue;
+ sect = obj->sect+sym.shndx;
+ if(sect->sym == nil) {
+ diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
+ continue;
+ }
+ s = sym.sym;
+ s->sub = sect->sym->sub;
+ sect->sym->sub = s;
+ s->type = sect->sym->type | SSUB;
+ if(!s->dynexport) {
+ s->dynimplib = nil; // satisfy dynimport
+ s->dynimpname = nil; // satisfy dynimport
+ }
+ s->value = sym.value;
+ s->size = sym.size;
+ 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 elf file: %r", pn);
+}
+
+static ElfSect*
+section(ElfObj *obj, char *name)
+{
+ int i;
+
+ for(i=0; i<obj->nsect; i++)
+ if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0)
+ return &obj->sect[i];
+ return nil;
+}
+
+static int
+map(ElfObj *obj, ElfSect *sect)
+{
+ if(sect->base != nil)
+ return 0;
+
+ if(sect->off+sect->size > obj->len) {
+ werrstr("elf section past end of file");
+ return -1;
+ }
+
+ sect->base = mal(sect->size);
+ werrstr("short read");
+ if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size)
+ return -1;
+
+ return 0;
+}
+
+static int
+readsym(ElfObj *obj, int i, ElfSym *sym)
+{
+ Sym *s;
+
+ if(i >= obj->nsymtab || i < 0) {
+ werrstr("invalid elf symbol index");
+ return -1;
+ }
+
+ if(obj->is64) {
+ ElfSymBytes64 *b;
+
+ b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b);
+ sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+ sym->value = obj->e->e64(b->value);
+ sym->size = obj->e->e64(b->size);
+ sym->shndx = obj->e->e16(b->shndx);
+ sym->bind = b->info>>4;
+ sym->type = b->info&0xf;
+ sym->other = b->other;
+ } else {
+ ElfSymBytes *b;
+
+ b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b);
+ sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+ sym->value = obj->e->e32(b->value);
+ sym->size = obj->e->e32(b->size);
+ sym->shndx = obj->e->e16(b->shndx);
+ sym->bind = b->info>>4;
+ sym->type = b->info&0xf;
+ sym->other = b->other;
+ }
+
+ s = nil;
+ if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
+ sym->name = ".got";
+ if(strcmp(sym->name, "__stack_chk_fail_local") == 0)
+ sym->other = 0; // rewrite hidden -> default visibility
+ switch(sym->type) {
+ case ElfSymTypeSection:
+ s = obj->sect[sym->shndx].sym;
+ break;
+ case ElfSymTypeObject:
+ case ElfSymTypeFunc:
+ case ElfSymTypeNone:
+ switch(sym->bind) {
+ case ElfSymBindGlobal:
+ if(sym->other != 2) {
+ s = lookup(sym->name, 0);
+ break;
+ }
+ // fall through
+ case ElfSymBindLocal:
+ s = lookup(sym->name, version);
+ break;
+ default:
+ werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
+ return -1;
+ }
+ break;
+ }
+ if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection)
+ s->type = SXREF;
+ sym->sym = s;
+
+ return 0;
+}
+
+int
+rbyoff(const void *va, const void *vb)
+{
+ Reloc *a, *b;
+
+ a = (Reloc*)va;
+ b = (Reloc*)vb;
+ if(a->off < b->off)
+ return -1;
+ if(a->off > b->off)
+ return +1;
+ return 0;
+}
+
+#define R(x, y) ((x)|((y)<<24))
+
+static int
+reltype(char *pn, int elftype, uchar *siz)
+{
+ switch(R(thechar, elftype)) {
+ default:
+ diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
+ case R('6', R_X86_64_PC32):
+ case R('6', R_X86_64_PLT32):
+ case R('6', R_X86_64_GOTPCREL):
+ case R('8', R_386_32):
+ case R('8', R_386_PC32):
+ case R('8', R_386_GOT32):
+ case R('8', R_386_PLT32):
+ case R('8', R_386_GOTOFF):
+ case R('8', R_386_GOTPC):
+ *siz = 4;
+ break;
+ case R('6', R_X86_64_64):
+ *siz = 8;
+ break;
+ }
+
+ return 256+elftype;
+}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
new file mode 100644
index 000000000..7e38db0e4
--- /dev/null
+++ b/src/cmd/ld/ldmacho.c
@@ -0,0 +1,794 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+ Copyright © 2004 Russ Cox.
+ Portions Copyright © 2008-2010 Google Inc.
+ Portions Copyright © 2010 The Go Authors.
+
+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 "l.h"
+#include "lib.h"
+
+enum {
+ MACHO_FAKE_GOTPCREL = 100, // from macho.h
+
+ N_EXT = 0x01,
+ N_TYPE = 0x1e,
+ N_STAB = 0xe0,
+};
+
+typedef struct MachoObj MachoObj;
+typedef struct MachoCmd MachoCmd;
+typedef struct MachoSeg MachoSeg;
+typedef struct MachoSect MachoSect;
+typedef struct MachoRel MachoRel;
+typedef struct MachoSymtab MachoSymtab;
+typedef struct MachoSym MachoSym;
+typedef struct MachoDysymtab MachoDysymtab;
+
+enum
+{
+ MachoCpuVax = 1,
+ MachoCpu68000 = 6,
+ MachoCpu386 = 7,
+ MachoCpuAmd64 = 0x1000007,
+ MachoCpuMips = 8,
+ MachoCpu98000 = 10,
+ MachoCpuHppa = 11,
+ MachoCpuArm = 12,
+ MachoCpu88000 = 13,
+ MachoCpuSparc = 14,
+ MachoCpu860 = 15,
+ MachoCpuAlpha = 16,
+ MachoCpuPower = 18,
+
+ MachoCmdSegment = 1,
+ MachoCmdSymtab = 2,
+ MachoCmdSymseg = 3,
+ MachoCmdThread = 4,
+ MachoCmdDysymtab = 11,
+ MachoCmdSegment64 = 25,
+
+ MachoFileObject = 1,
+ MachoFileExecutable = 2,
+ MachoFileFvmlib = 3,
+ MachoFileCore = 4,
+ MachoFilePreload = 5,
+};
+
+struct MachoSeg
+{
+ char name[16+1];
+ uint64 vmaddr;
+ uint64 vmsize;
+ uint32 fileoff;
+ uint32 filesz;
+ uint32 maxprot;
+ uint32 initprot;
+ uint32 nsect;
+ uint32 flags;
+ MachoSect *sect;
+};
+
+struct MachoSect
+{
+ char name[16+1];
+ char segname[16+1];
+ uint64 addr;
+ uint64 size;
+ uint32 off;
+ uint32 align;
+ uint32 reloff;
+ uint32 nreloc;
+ uint32 flags;
+ uint32 res1;
+ uint32 res2;
+ Sym *sym;
+
+ MachoRel *rel;
+};
+
+struct MachoRel
+{
+ uint32 addr;
+ uint32 symnum;
+ uint8 pcrel;
+ uint8 length;
+ uint8 extrn;
+ uint8 type;
+ uint8 scattered;
+ uint32 value;
+};
+
+struct MachoSymtab
+{
+ uint32 symoff;
+ uint32 nsym;
+ uint32 stroff;
+ uint32 strsize;
+
+ char *str;
+ MachoSym *sym;
+};
+
+struct MachoSym
+{
+ char *name;
+ uint8 type;
+ uint8 sectnum;
+ uint16 desc;
+ char kind;
+ uint64 value;
+ Sym *sym;
+};
+
+struct MachoDysymtab
+{
+ uint32 ilocalsym;
+ uint32 nlocalsym;
+ uint32 iextdefsym;
+ uint32 nextdefsym;
+ uint32 iundefsym;
+ uint32 nundefsym;
+ uint32 tocoff;
+ uint32 ntoc;
+ uint32 modtaboff;
+ uint32 nmodtab;
+ uint32 extrefsymoff;
+ uint32 nextrefsyms;
+ uint32 indirectsymoff;
+ uint32 nindirectsyms;
+ uint32 extreloff;
+ uint32 nextrel;
+ uint32 locreloff;
+ uint32 nlocrel;
+ uint32 *indir;
+};
+
+struct MachoCmd
+{
+ int type;
+ uint32 off;
+ uint32 size;
+ MachoSeg seg;
+ MachoSymtab sym;
+ MachoDysymtab dsym;
+};
+
+struct MachoObj
+{
+ Biobuf *f;
+ int64 base; // off in f where Mach-O begins
+ int64 len; // length of Mach-O
+ int is64;
+ char *name;
+
+ Endian *e;
+ uint cputype;
+ uint subcputype;
+ uint32 filetype;
+ uint32 flags;
+ MachoCmd *cmd;
+ uint ncmd;
+};
+
+static int
+unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
+{
+ uint32 (*e4)(uchar*);
+ uint64 (*e8)(uchar*);
+ MachoSect *s;
+ int i;
+
+ e4 = m->e->e32;
+ e8 = m->e->e64;
+
+ c->type = type;
+ c->size = sz;
+ switch(type){
+ default:
+ return -1;
+ case MachoCmdSegment:
+ if(sz < 56)
+ return -1;
+ strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+ c->seg.vmaddr = e4(p+24);
+ c->seg.vmsize = e4(p+28);
+ c->seg.fileoff = e4(p+32);
+ c->seg.filesz = e4(p+36);
+ c->seg.maxprot = e4(p+40);
+ c->seg.initprot = e4(p+44);
+ c->seg.nsect = e4(p+48);
+ c->seg.flags = e4(p+52);
+ c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+ if(sz < 56+c->seg.nsect*68)
+ return -1;
+ p += 56;
+ for(i=0; i<c->seg.nsect; i++) {
+ s = &c->seg.sect[i];
+ strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+ strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+ s->addr = e4(p+32);
+ s->size = e4(p+36);
+ s->off = e4(p+40);
+ s->align = e4(p+44);
+ s->reloff = e4(p+48);
+ s->nreloc = e4(p+52);
+ s->flags = e4(p+56);
+ s->res1 = e4(p+60);
+ s->res2 = e4(p+64);
+ p += 68;
+ }
+ break;
+ case MachoCmdSegment64:
+ if(sz < 72)
+ return -1;
+ strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+ c->seg.vmaddr = e8(p+24);
+ c->seg.vmsize = e8(p+32);
+ c->seg.fileoff = e8(p+40);
+ c->seg.filesz = e8(p+48);
+ c->seg.maxprot = e4(p+56);
+ c->seg.initprot = e4(p+60);
+ c->seg.nsect = e4(p+64);
+ c->seg.flags = e4(p+68);
+ c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+ if(sz < 72+c->seg.nsect*80)
+ return -1;
+ p += 72;
+ for(i=0; i<c->seg.nsect; i++) {
+ s = &c->seg.sect[i];
+ strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+ strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+ s->addr = e8(p+32);
+ s->size = e8(p+40);
+ s->off = e4(p+48);
+ s->align = e4(p+52);
+ s->reloff = e4(p+56);
+ s->nreloc = e4(p+60);
+ s->flags = e4(p+64);
+ s->res1 = e4(p+68);
+ s->res2 = e4(p+72);
+ // p+76 is reserved
+ p += 80;
+ }
+ break;
+ case MachoCmdSymtab:
+ if(sz < 24)
+ return -1;
+ c->sym.symoff = e4(p+8);
+ c->sym.nsym = e4(p+12);
+ c->sym.stroff = e4(p+16);
+ c->sym.strsize = e4(p+20);
+ break;
+ case MachoCmdDysymtab:
+ if(sz < 80)
+ return -1;
+ c->dsym.ilocalsym = e4(p+8);
+ c->dsym.nlocalsym = e4(p+12);
+ c->dsym.iextdefsym = e4(p+16);
+ c->dsym.nextdefsym = e4(p+20);
+ c->dsym.iundefsym = e4(p+24);
+ c->dsym.nundefsym = e4(p+28);
+ c->dsym.tocoff = e4(p+32);
+ c->dsym.ntoc = e4(p+36);
+ c->dsym.modtaboff = e4(p+40);
+ c->dsym.nmodtab = e4(p+44);
+ c->dsym.extrefsymoff = e4(p+48);
+ c->dsym.nextrefsyms = e4(p+52);
+ c->dsym.indirectsymoff = e4(p+56);
+ c->dsym.nindirectsyms = e4(p+60);
+ c->dsym.extreloff = e4(p+64);
+ c->dsym.nextrel = e4(p+68);
+ c->dsym.locreloff = e4(p+72);
+ c->dsym.nlocrel = e4(p+76);
+ break;
+ }
+ return 0;
+}
+
+static int
+macholoadrel(MachoObj *m, MachoSect *sect)
+{
+ MachoRel *rel, *r;
+ uchar *buf, *p;
+ int i, n;
+ uint32 v;
+
+ if(sect->rel != nil || sect->nreloc == 0)
+ return 0;
+ rel = mal(sect->nreloc * sizeof r[0]);
+ n = sect->nreloc * 8;
+ buf = mal(n);
+ if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
+ return -1;
+ for(i=0; i<sect->nreloc; i++) {
+ r = &rel[i];
+ p = buf+i*8;
+ r->addr = m->e->e32(p);
+
+ // TODO(rsc): Wrong interpretation for big-endian bitfields?
+ if(r->addr & 0x80000000) {
+ // scatterbrained relocation
+ r->scattered = 1;
+ v = r->addr >> 24;
+ r->addr &= 0xFFFFFF;
+ r->type = v & 0xF;
+ v >>= 4;
+ r->length = 1<<(v&3);
+ v >>= 2;
+ r->pcrel = v & 1;
+ r->value = m->e->e32(p+4);
+ } else {
+ v = m->e->e32(p+4);
+ r->symnum = v & 0xFFFFFF;
+ v >>= 24;
+ r->pcrel = v&1;
+ v >>= 1;
+ r->length = 1<<(v&3);
+ v >>= 2;
+ r->extrn = v&1;
+ v >>= 1;
+ r->type = v;
+ }
+ }
+ sect->rel = rel;
+ return 0;
+}
+
+static int
+macholoaddsym(MachoObj *m, MachoDysymtab *d)
+{
+ uchar *p;
+ int i, n;
+
+ n = d->nindirectsyms;
+
+ p = mal(n*4);
+ if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
+ return -1;
+
+ d->indir = (uint32*)p;
+ for(i=0; i<n; i++)
+ d->indir[i] = m->e->e32(p+4*i);
+ return 0;
+}
+
+static int
+macholoadsym(MachoObj *m, MachoSymtab *symtab)
+{
+ char *strbuf;
+ uchar *symbuf, *p;
+ int i, n, symsize;
+ MachoSym *sym, *s;
+ uint32 v;
+
+ if(symtab->sym != nil)
+ return 0;
+
+ strbuf = mal(symtab->strsize);
+ if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
+ return -1;
+
+ symsize = 12;
+ if(m->is64)
+ symsize = 16;
+ n = symtab->nsym * symsize;
+ symbuf = mal(n);
+ if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
+ return -1;
+ sym = mal(symtab->nsym * sizeof sym[0]);
+ p = symbuf;
+ for(i=0; i<symtab->nsym; i++) {
+ s = &sym[i];
+ v = m->e->e32(p);
+ if(v >= symtab->strsize)
+ return -1;
+ s->name = strbuf + v;
+ s->type = p[4];
+ s->sectnum = p[5];
+ s->desc = m->e->e16(p+6);
+ if(m->is64)
+ s->value = m->e->e64(p+8);
+ else
+ s->value = m->e->e32(p+8);
+ p += symsize;
+ }
+ symtab->str = strbuf;
+ symtab->sym = sym;
+ return 0;
+}
+
+void
+ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int i, j, is64;
+ uchar hdr[7*4], *cmdp;
+ uchar tmp[4];
+ uchar *dat;
+ ulong ncmd, cmdsz, ty, sz, off;
+ MachoObj *m;
+ Endian *e;
+ int64 base;
+ MachoSect *sect;
+ MachoRel *rel;
+ Sym *s, *outer;
+ MachoCmd *c;
+ MachoSymtab *symtab;
+ MachoDysymtab *dsymtab;
+ MachoSym *sym;
+ Reloc *r, *rp;
+ char *name;
+
+ version++;
+ base = Boffset(f);
+ if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
+ goto bad;
+
+ if((be.e32(hdr)&~1) == 0xFEEDFACE){
+ e = &be;
+ }else if((le.e32(hdr)&~1) == 0xFEEDFACE){
+ e = &le;
+ }else{
+ werrstr("bad magic - not mach-o file");
+ goto bad;
+ }
+
+ is64 = e->e32(hdr) == 0xFEEDFACF;
+ ncmd = e->e32(hdr+4*4);
+ cmdsz = e->e32(hdr+5*4);
+ if(ncmd > 0x10000 || cmdsz >= 0x01000000){
+ werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
+ goto bad;
+ }
+ if(is64)
+ Bread(f, tmp, 4); // skip reserved word in header
+
+ m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
+ m->f = f;
+ m->e = e;
+ m->cputype = e->e32(hdr+1*4);
+ m->subcputype = e->e32(hdr+2*4);
+ m->filetype = e->e32(hdr+3*4);
+ m->ncmd = ncmd;
+ m->flags = e->e32(hdr+6*4);
+ m->is64 = is64;
+ m->base = base;
+ m->len = len;
+ m->name = pn;
+
+ switch(thechar) {
+ default:
+ diag("%s: mach-o %s unimplemented", thestring);
+ return;
+ case '6':
+ if(e != &le || m->cputype != MachoCpuAmd64) {
+ diag("%s: mach-o object but not amd64", pn);
+ return;
+ }
+ break;
+ case '8':
+ if(e != &le || m->cputype != MachoCpu386) {
+ diag("%s: mach-o object but not 386", pn);
+ return;
+ }
+ break;
+ }
+
+ m->cmd = (MachoCmd*)(m+1);
+ off = sizeof hdr;
+ cmdp = (uchar*)(m->cmd+ncmd);
+ if(Bread(f, cmdp, cmdsz) != cmdsz){
+ werrstr("reading cmds: %r");
+ goto bad;
+ }
+
+ // read and parse load commands
+ c = nil;
+ symtab = nil;
+ dsymtab = nil;
+ for(i=0; i<ncmd; i++){
+ ty = e->e32(cmdp);
+ sz = e->e32(cmdp+4);
+ m->cmd[i].off = off;
+ unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
+ cmdp += sz;
+ off += sz;
+ if(ty == MachoCmdSymtab) {
+ if(symtab != nil) {
+ werrstr("multiple symbol tables");
+ goto bad;
+ }
+ symtab = &m->cmd[i].sym;
+ macholoadsym(m, symtab);
+ }
+ if(ty == MachoCmdDysymtab) {
+ dsymtab = &m->cmd[i].dsym;
+ macholoaddsym(m, dsymtab);
+ }
+ if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
+ if(c != nil) {
+ werrstr("multiple load commands");
+ goto bad;
+ }
+ c = &m->cmd[i];
+ }
+ }
+
+ // load text and data segments into memory.
+ // they are not as small as the load commands, but we'll need
+ // the memory anyway for the symbol images, so we might
+ // as well use one large chunk.
+ if(c == nil) {
+ werrstr("no load command");
+ goto bad;
+ }
+ if(symtab == nil) {
+ // our work is done here - no symbols means nothing can refer to this file
+ return;
+ }
+
+ if(c->seg.fileoff+c->seg.filesz >= len) {
+ werrstr("load segment out of range");
+ goto bad;
+ }
+
+ dat = mal(c->seg.filesz);
+ if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
+ werrstr("cannot load object data: %r");
+ goto bad;
+ }
+
+ for(i=0; i<c->seg.nsect; i++) {
+ sect = &c->seg.sect[i];
+ if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
+ continue;
+ if(strcmp(sect->name, "__eh_frame") == 0)
+ continue;
+ name = smprint("%s(%s/%s)", pn, sect->segname, sect->name);
+ s = lookup(name, version);
+ if(s->type != 0) {
+ werrstr("duplicate %s/%s", sect->segname, sect->name);
+ goto bad;
+ }
+ free(name);
+ s->p = dat + sect->addr - c->seg.vmaddr;
+ s->np = sect->size;
+ s->size = s->np;
+
+ if(strcmp(sect->segname, "__TEXT") == 0) {
+ if(strcmp(sect->name, "__text") == 0)
+ s->type = STEXT;
+ else
+ s->type = SRODATA;
+ } else {
+ s->type = SDATA;
+ }
+ if(s->type == STEXT) {
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ }
+ sect->sym = s;
+ }
+
+ // enter sub-symbols into symbol table.
+ // have to guess sizes from next symbol.
+ for(i=0; i<symtab->nsym; i++) {
+ int v;
+ sym = &symtab->sym[i];
+ if(sym->type&N_STAB)
+ continue;
+ // TODO: check sym->type against outer->type.
+ name = sym->name;
+ if(name[0] == '_' && name[1] != '\0')
+ name++;
+ v = 0;
+ if(!(sym->type&N_EXT))
+ v = version;
+ s = lookup(name, v);
+ sym->sym = s;
+ if(sym->sectnum == 0) // undefined
+ continue;
+ if(sym->sectnum > c->seg.nsect) {
+ werrstr("reference to invalid section %d", sym->sectnum);
+ goto bad;
+ }
+ sect = &c->seg.sect[sym->sectnum-1];
+ outer = sect->sym;
+ if(outer == nil) {
+ werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
+ continue;
+ }
+ s->type = outer->type | SSUB;
+ s->sub = outer->sub;
+ outer->sub = s;
+ s->outer = outer;
+ s->value = sym->value - sect->addr;
+ if(i+1 < symtab->nsym)
+ s->size = (sym+1)->value - sym->value;
+ else
+ s->size = sect->addr + sect->size - sym->value;
+ if(!s->dynexport) {
+ s->dynimplib = nil; // satisfy dynimport
+ s->dynimpname = nil; // satisfy dynimport
+ }
+ if(outer->type == STEXT) {
+ Prog *p;
+
+ if(s->text != P)
+ diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
+ // build a TEXT instruction with a unique pc
+ // just to make the rest of the linker happy.
+ // TODO: this is too 6l-specific ?
+ 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;
+ }
+ sym->sym = s;
+ }
+
+ // load relocations
+ for(i=0; i<c->seg.nsect; i++) {
+ sect = &c->seg.sect[i];
+ if((s = sect->sym) == S)
+ continue;
+ macholoadrel(m, sect);
+ if(sect->rel == nil)
+ continue;
+ r = mal(sect->nreloc*sizeof r[0]);
+ rp = r;
+ rel = sect->rel;
+ for(j=0; j<sect->nreloc; j++, rel++) {
+ if(rel->scattered) {
+ int k;
+ MachoSect *ks;
+
+ if(thechar != '8')
+ diag("unexpected scattered relocation");
+
+ // on 386, rewrite scattered 4/1 relocation into
+ // the pseudo-pc-relative reference that it is.
+ // assume that the second in the pair is in this section
+ // and use that as the pc-relative base.
+ if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc ||
+ !(rel+1)->scattered || (rel+1)->type != 1 ||
+ (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
+ werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
+ goto bad;
+ }
+ rp->siz = rel->length;
+ rp->off = rel->addr;
+
+ // NOTE(rsc): I haven't worked out why (really when)
+ // we should ignore the addend on a
+ // scattered relocation, but it seems that the
+ // common case is we ignore it.
+ // It's likely that this is not strictly correct
+ // and that the math should look something
+ // like the non-scattered case below.
+ rp->add = 0;
+
+ // want to make it pc-relative aka relative to rp->off+4
+ // but the scatter asks for relative to off = (rel+1)->value - sect->addr.
+ // adjust rp->add accordingly.
+ rp->type = D_PCREL;
+ rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
+
+ // now consider the desired symbol.
+ // find the section where it lives.
+ for(k=0; k<c->seg.nsect; k++) {
+ ks = &c->seg.sect[k];
+ if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
+ goto foundk;
+ }
+ werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
+ goto bad;
+ foundk:
+ if(ks->sym != S) {
+ rp->sym = ks->sym;
+ rp->add += rel->value - ks->addr;
+ } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
+ // handle reference to __IMPORT/__pointers.
+ // how much worse can this get?
+ // why are we supporting 386 on the mac anyway?
+ rp->type = 512 + MACHO_FAKE_GOTPCREL;
+ // figure out which pointer this is a reference to.
+ k = ks->res1 + (rel->value - ks->addr) / 4;
+ // load indirect table for __pointers
+ // fetch symbol number
+ if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
+ werrstr("invalid scattered relocation: indirect symbol reference out of range");
+ goto bad;
+ }
+ k = dsymtab->indir[k];
+ if(k < 0 || k >= symtab->nsym) {
+ werrstr("invalid scattered relocation: symbol reference out of range");
+ goto bad;
+ }
+ rp->sym = symtab->sym[k].sym;
+ } else {
+ werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
+ goto bad;
+ }
+ rp++;
+ // skip #1 of 2 rel; continue skips #2 of 2.
+ rel++;
+ j++;
+ continue;
+ }
+
+ rp->siz = rel->length;
+ rp->type = 512 + (rel->type<<1) + rel->pcrel;
+ rp->off = rel->addr;
+
+ rp->add = e->e32(s->p+rp->off);
+ // For i386 Mach-O PC-relative, the addend is written such that
+ // it *is* the PC being subtracted. Use that to make
+ // it match our version of PC-relative.
+ if(rel->pcrel && thechar == '8')
+ rp->add += rp->off+rp->siz;
+ if(!rel->extrn) {
+ if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
+ werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
+ goto bad;
+ }
+ rp->sym = c->seg.sect[rel->symnum-1].sym;
+ if(rp->sym == nil) {
+ werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
+ goto bad;
+ }
+ // References to symbols in other sections
+ // include that information in the addend.
+ // We only care about the delta from the
+ // section base.
+ if(thechar == '8')
+ rp->add -= c->seg.sect[rel->symnum-1].addr;
+ } else {
+ if(rel->symnum >= symtab->nsym) {
+ werrstr("invalid relocation: symbol reference out of range");
+ goto bad;
+ }
+ rp->sym = symtab->sym[rel->symnum].sym;
+ }
+ rp++;
+ }
+ qsort(r, rp - r, sizeof r[0], rbyoff);
+ s->r = r;
+ s->nr = rp - r;
+ }
+ return;
+
+bad:
+ diag("%s: malformed mach-o file: %r", pn);
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 1af9f7a41..ae77247c3 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -1,5 +1,6 @@
-// Derived from Inferno utils/6l/obj.c
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -118,7 +119,7 @@ addlib(char *src, char *obj)
}
for(; i<histfrogp; i++) {
- snprint(comp, sizeof comp, histfrog[i]->name+1);
+ snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
@@ -146,6 +147,22 @@ addlib(char *src, char *obj)
strcat(name, comp);
}
cleanname(name);
+
+ // runtime.a -> runtime
+ p = nil;
+ if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
+ p = name+strlen(name)-2;
+ *p = '\0';
+ }
+
+ // already loaded?
+ for(i=0; i<libraryp; i++)
+ if(strcmp(library[i].pkg, name) == 0)
+ return;
+
+ // runtime -> runtime.a for search
+ if(p != nil)
+ *p = '.';
if(search) {
// try dot, -L "libdir", and then goroot.
@@ -159,8 +176,8 @@ addlib(char *src, char *obj)
cleanname(pname);
/* runtime.a -> runtime */
- if(strlen(name) > 2 && name[strlen(name)-2] == '.')
- name[strlen(name)-2] = '\0';
+ if(p != nil)
+ *p = '\0';
if(debug['v'])
Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
@@ -186,9 +203,9 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(strcmp(file, library[i].file) == 0)
return;
- if(debug['v'])
+ if(debug['v'] > 1)
Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
- cputime(), srcref, objref, file, pkg);
+ cputime(), srcref, objref, file, pkg);
if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp;
@@ -219,8 +236,6 @@ loadlib(void)
{
char pname[1024];
int i, found;
- int32 h;
- Sym *s;
found = 0;
for(i=0; i<nlibdir; i++) {
@@ -233,47 +248,51 @@ loadlib(void)
break;
}
}
- if(!found) Bprint(&bso, "warning: unable to find runtime.a\n");
+ if(!found)
+ Bprint(&bso, "warning: unable to find runtime.a\n");
-loop:
- xrefresolv = 0;
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
objfile(library[i].file, library[i].pkg);
}
+}
- if(xrefresolv)
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->type == SXREF)
- goto loop;
-
+/*
+ * look for the next file in an archive.
+ * adapted from libmach.
+ */
+int
+nextar(Biobuf *bp, int off, struct ar_hdr *a)
+{
+ int r;
+ int32 arsize;
+
+ if (off&01)
+ off++;
+ Bseek(bp, off, 0);
+ r = Bread(bp, a, SAR_HDR);
+ if(r != SAR_HDR)
+ return 0;
+ if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag)))
+ return -1;
+ arsize = strtol(a->size, 0, 0);
+ if (arsize&1)
+ arsize++;
+ return arsize + SAR_HDR;
}
void
objfile(char *file, char *pkg)
{
- int32 off, esym, cnt, l;
- int work;
+ int32 off, l;
Biobuf *f;
- Sym *s;
char magbuf[SARMAG];
- char name[100], pname[150];
+ char pname[150];
struct ar_hdr arhdr;
- char *e, *start, *stop, *x;
pkg = smprint("%i", pkg);
- if(file[0] == '-' && file[1] == 'l') { // TODO: fix this
- if(debug['9'])
- sprint(name, "/%s/lib/lib", thestring);
- else
- sprint(name, "/usr/%clib/lib", thechar);
- strcat(name, file+2);
- strcat(name, ".a");
- file = name;
- }
if(debug['v'])
Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
Bflush(&bso);
@@ -291,9 +310,10 @@ objfile(char *file, char *pkg)
Bterm(f);
return;
}
-
- l = Bread(f, &arhdr, SAR_HDR);
- if(l != SAR_HDR) {
+
+ /* skip over __.SYMDEF */
+ off = Boffset(f);
+ if((l = nextar(f, off, &arhdr)) <= 0) {
diag("%s: short read on archive file symbol header", file);
goto out;
}
@@ -301,88 +321,52 @@ objfile(char *file, char *pkg)
diag("%s: first entry not symbol header", file);
goto out;
}
-
- esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
- off = SARMAG + SAR_HDR;
-
- if(debug['u']) {
- struct ar_hdr pkghdr;
- int n;
-
- // Read next ar header to check for package safe bit.
- Bseek(f, esym+(esym&1), 0);
- l = Bread(f, &pkghdr, SAR_HDR);
- if(l != SAR_HDR) {
- diag("%s: short read on second archive header", file);
- goto out;
- }
- if(strncmp(pkghdr.name, pkgname, strlen(pkgname))) {
- diag("%s: second entry not package header", file);
- goto out;
- }
- n = atolwhex(pkghdr.size);
- ldpkg(f, pkg, n, file, Pkgdef);
+ off += l;
+
+ /* skip over (or process) __.PKGDEF */
+ if((l = nextar(f, off, &arhdr)) <= 0) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
}
+ if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
+ diag("%s: second entry not package header", file);
+ goto out;
+ }
+ off += l;
+
+ if(debug['u'])
+ ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
/*
- * just bang the whole symbol file into memory
+ * load all the object files from the archive now.
+ * this gives us sequential file access and keeps us
+ * from needing to come back later to pick up more
+ * objects. it breaks the usual C archive model, but
+ * this is Go, not C. the common case in Go is that
+ * we need to load all the objects, and then we throw away
+ * the individual symbols that are unused.
+ *
+ * loading every object will also make it possible to
+ * load foreign objects not referenced by __.SYMDEF.
*/
- Bseek(f, off, 0);
- cnt = esym - off;
- start = mal(cnt + 10);
- cnt = Bread(f, start, cnt);
- if(cnt <= 0){
- Bterm(f);
- return;
- }
- stop = &start[cnt];
- memset(stop, 0, 10);
-
- work = 1;
- while(work) {
- if(debug['v'])
- Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
- Bflush(&bso);
- work = 0;
- for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
- x = expandpkg(e+5, pkg);
- s = lookup(x, 0);
- if(x != e+5)
- free(x);
- if(s->type != SXREF)
- continue;
- sprint(pname, "%s(%s)", file, s->name);
- if(debug['v'])
- Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
- Bflush(&bso);
- l = e[1] & 0xff;
- l |= (e[2] & 0xff) << 8;
- l |= (e[3] & 0xff) << 16;
- l |= (e[4] & 0xff) << 24;
- Bseek(f, l, 0);
- l = Bread(f, &arhdr, SAR_HDR);
- if(l != SAR_HDR)
- goto bad;
- if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
- goto bad;
- l = SARNAME;
- while(l > 0 && arhdr.name[l-1] == ' ')
- l--;
- sprint(pname, "%s(%.*s)", file, l, arhdr.name);
- l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
- if(s->type == SXREF) {
- diag("%s: failed to load: %s", file, s->name);
- errorexit();
- }
- work = 1;
- xrefresolv = 1;
+ for(;;) {
+ l = nextar(f, off, &arhdr);
+ if(l == 0)
+ break;
+ if(l < 0) {
+ diag("%s: malformed archive", file);
+ goto out;
}
+ off += l;
+
+ l = SARNAME;
+ while(l > 0 && arhdr.name[l-1] == ' ')
+ l--;
+ snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
+ l = atolwhex(arhdr.size);
+ ldobj(f, pkg, l, pname, ArchiveObj);
}
- return;
-bad:
- diag("%s: bad or out of date archive", file);
out:
Bterm(f);
}
@@ -390,32 +374,38 @@ out:
void
ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
{
- static int files;
- static char **filen;
- char **nfilen, *line;
- int i, n, c1, c2, c3;
+ char *line;
+ int n, c1, c2, c3, c4;
+ uint32 magic;
vlong import0, import1, eof;
char src[1024];
eof = Boffset(f) + len;
src[0] = '\0';
- // don't load individual object more than once.
- // happens with import of .6 files because of loop in xresolv.
- // doesn't happen with .a because SYMDEF is consulted
- // first to decide whether each individual object file is needed.
- for(i=0; i<files; i++)
- if(strcmp(filen[i], pn) == 0)
- return;
+ pn = strdup(pn);
+
+ USED(c4);
+ USED(magic);
- if((files&15) == 0){
- nfilen = malloc((files+16)*sizeof(char*));
- memmove(nfilen, filen, files*sizeof(char*));
- free(filen);
- filen = nfilen;
+ c1 = Bgetc(f);
+ c2 = Bgetc(f);
+ c3 = Bgetc(f);
+ c4 = Bgetc(f);
+ Bungetc(f);
+ Bungetc(f);
+ Bungetc(f);
+ Bungetc(f);
+
+ magic = c1<<24 | c2<<16 | c3<<8 | c4;
+ if(magic == 0x7f454c46) { // \x7F E L F
+ ldelf(f, pkg, len, pn);
+ return;
+ }
+ if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
+ ldmacho(f, pkg, len, pn);
+ return;
}
- pn = strdup(pn);
- filen[files++] = pn;
/* check the header */
line = Brdline(f, '\n');
@@ -478,7 +468,7 @@ lookup(char *symb, int v)
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
- for(s = hash[h]; s != S; s = s->link)
+ for(s = hash[h]; s != S; s = s->hash)
if(s->version == v)
if(memcmp(s->name, symb, l) == 0)
return s;
@@ -487,14 +477,18 @@ lookup(char *symb, int v)
if(debug['v'] > 1)
Bprint(&bso, "lookup %s\n", symb);
+ s->dynid = -1;
+ s->plt = -1;
+ s->got = -1;
s->name = mal(l + 1);
memmove(s->name, symb, l);
- s->link = hash[h];
+ s->hash = hash[h];
s->type = 0;
s->version = v;
s->value = 0;
s->sig = 0;
+ s->size = 0;
hash[h] = s;
nsymbol++;
return s;
@@ -607,8 +601,13 @@ nuxiinit(void)
if(i < 1)
inuxi1[i] = c;
inuxi4[i] = c;
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
+ if(c == i) {
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ } else {
+ inuxi8[i] = c+4;
+ inuxi8[i+4] = c;
+ }
fnuxi4[i] = c;
fnuxi8[i] = c;
fnuxi8[i+4] = c+4;
@@ -732,21 +731,6 @@ ieeedtod(Ieee *ieeep)
}
void
-undefsym(Sym *s)
-{
- int n;
-
- n = imports;
- if(s->value != 0)
- diag("value != 0 on SXREF");
- if(n >= 1<<Rindex)
- diag("import index %d out of range", n);
- s->value = n<<Roffset;
- s->type = SUNDEF;
- imports++;
-}
-
-void
zerosig(char *sp)
{
Sym *s;
@@ -755,47 +739,6 @@ zerosig(char *sp)
s->sig = 0;
}
-void
-readundefs(char *f, int t)
-{
- int i, n;
- Sym *s;
- Biobuf *b;
- char *l, buf[256], *fields[64];
-
- if(f == nil)
- return;
- b = Bopen(f, OREAD);
- if(b == nil){
- diag("could not open %s: %r", f);
- errorexit();
- }
- while((l = Brdline(b, '\n')) != nil){
- n = Blinelen(b);
- if(n >= sizeof(buf)){
- diag("%s: line too long", f);
- errorexit();
- }
- memmove(buf, l, n);
- buf[n-1] = '\0';
- n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
- if(n == nelem(fields)){
- diag("%s: bad format", f);
- errorexit();
- }
- for(i = 0; i < n; i++){
- s = lookup(fields[i], 0);
- s->type = SXREF;
- s->subtype = t;
- if(t == SIMPORT)
- nimports++;
- else
- nexports++;
- }
- }
- Bterm(b);
-}
-
int32
Bget4(Biobuf *f)
{
@@ -829,15 +772,22 @@ mal(uint32 n)
{
void *v;
- while(n & 7)
- n++;
+ n = (n+7)&~7;
if(n > NHUNK) {
v = malloc(n);
+ if(v == nil) {
+ diag("out of memory");
+ errorexit();
+ }
memset(v, 0, n);
return v;
}
if(n > nhunk) {
hunk = malloc(NHUNK);
+ if(hunk == nil) {
+ diag("out of memory");
+ errorexit();
+ }
nhunk = NHUNK;
}
@@ -849,6 +799,16 @@ mal(uint32 n)
return v;
}
+void
+unmal(void *v, uint32 n)
+{
+ n = (n+7)&~7;
+ if(hunk - n == v) {
+ hunk -= n;
+ nhunk += n;
+ }
+}
+
// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
/*
* Convert raw string to the prefix that will be used in the symbol table.
@@ -901,3 +861,211 @@ iconv(Fmt *fp)
return 0;
}
+void
+mangle(char *file)
+{
+ fprint(2, "%s: mangled input file\n", file);
+ errorexit();
+}
+
+Section*
+addsection(Segment *seg, char *name, int rwx)
+{
+ Section **l;
+ Section *sect;
+
+ for(l=&seg->sect; *l; l=&(*l)->next)
+ ;
+ sect = mal(sizeof *sect);
+ sect->rwx = rwx;
+ sect->name = name;
+ sect->seg = seg;
+ *l = sect;
+ return sect;
+}
+
+void
+ewrite(int fd, void *buf, int n)
+{
+ if(write(fd, buf, n) < 0) {
+ diag("write error: %r");
+ errorexit();
+ }
+}
+
+void
+pclntab(void)
+{
+ vlong oldpc;
+ Prog *p;
+ int32 oldlc, v, s;
+ Sym *sym;
+ uchar *bp;
+
+ sym = lookup("pclntab", 0);
+ sym->type = SRODATA;
+ sym->reachable = 1;
+ if(debug['s'])
+ return;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(debug['O'])
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ continue;
+ }
+ if(debug['O'])
+ Bprint(&bso, "\t\t%6d", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ symgrow(sym, lcsize+1);
+ bp = sym->p + lcsize;
+ *bp = s+128; /* 129-255 +pc */
+ if(debug['O'])
+ Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ symgrow(sym, lcsize+5);
+ bp = sym->p + lcsize;
+ *bp++ = 0; /* 0 vv +lc */
+ *bp++ = s>>24;
+ *bp++ = s>>16;
+ *bp++ = s>>8;
+ *bp = s;
+ if(debug['O']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%d(%d,%d)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%d(%d,%d)\n",
+ s, 0, s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ symgrow(sym, lcsize+1);
+ bp = sym->p + lcsize;
+ if(s > 0) {
+ *bp = 0+s; /* 1-64 +lc */
+ if(debug['O']) {
+ Bprint(&bso, " lc+%d(%d)\n", s, 0+s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ } else {
+ *bp = 64-s; /* 65-128 -lc */
+ if(debug['O']) {
+ Bprint(&bso, " lc%d(%d)\n", s, 64-s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ }
+ if(lcsize & 1) {
+ symgrow(sym, lcsize+1);
+ sym->p[lcsize] = 129;
+ lcsize++;
+ }
+ sym->size = lcsize;
+ lcsize = 0;
+
+ if(debug['v'] || debug['O'])
+ Bprint(&bso, "lcsize = %d\n", lcsize);
+ Bflush(&bso);
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ int32 dwn[LOG], cnt[LOG];
+ Prog *lst[LOG], *last;
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1;
+ else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ last = nil;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(p->link == P) {
+ if(cursym->next)
+ p->forwd = cursym->next->text;
+ break;
+ }
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+ }
+}
+
+uint16
+le16(uchar *b)
+{
+ return b[0] | b[1]<<8;
+}
+
+uint32
+le32(uchar *b)
+{
+ return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+}
+
+uint64
+le64(uchar *b)
+{
+ return le32(b) | (uint64)le32(b+4)<<32;
+}
+
+uint16
+be16(uchar *b)
+{
+ return b[0]<<8 | b[1];
+}
+
+uint32
+be32(uchar *b)
+{
+ return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
+}
+
+uint64
+be64(uchar *b)
+{
+ return (uvlong)be32(b)<<32 | be32(b+4);
+}
+
+Endian be = { be16, be32, be64 };
+Endian le = { le16, le32, le64 };
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 652d845fb..bcf297116 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -40,6 +40,34 @@ struct Library
char *pkg; // import path
};
+// Terrible but standard terminology.
+// A segment describes a block of file to load into memory.
+// A section further describes the pieces of that block for
+// use in debuggers and such.
+
+typedef struct Segment Segment;
+typedef struct Section Section;
+
+struct Segment
+{
+ uchar rwx; // permission as usual unix bits (5 = r-x etc)
+ uvlong vaddr; // virtual address
+ uvlong len; // length in memory
+ uvlong fileoff; // file offset
+ uvlong filelen; // length on disk
+ Section* sect;
+};
+
+struct Section
+{
+ uchar rwx;
+ char *name;
+ uvlong vaddr;
+ uvlong len;
+ Section *next; // in segment list
+ Segment *seg;
+};
+
extern char symname[];
extern char *libdir[];
extern int nlibdir;
@@ -64,11 +92,18 @@ EXTERN uchar inuxi8[8];
EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
+EXTERN int ndynexp;
+
+EXTERN Segment segtext;
+EXTERN Segment segdata;
+EXTERN Segment segsym;
void addlib(char *src, char *obj);
void addlibpath(char *srcref, char *objref, char *file, char *pkg);
+Section* addsection(Segment*, char*, int);
void copyhistfrog(char *buf, int nbuf);
void addhist(int32 line, int type);
+void asmlc(void);
void histtoauto(void);
void collapsefrog(Sym *s);
Sym* lookup(char *symb, int v);
@@ -83,20 +118,82 @@ void readundefs(char *f, int t);
int32 Bget4(Biobuf *f);
void loadlib(void);
void errorexit(void);
+void mangle(char*);
void objfile(char *file, char *pkg);
void libinit(void);
+void pclntab(void);
+void symtab(void);
void Lflag(char *arg);
void usage(void);
+void adddynrel(Sym*, Reloc*);
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 ldpkg(Biobuf*, char*, int64, char*, int);
void mark(Sym *s);
+void mkfwd(void);
char* expandpkg(char*, char*);
void deadcode(void);
+void ewrite(int, void*, int);
+Reloc* addrel(Sym*);
+void codeblk(int32, int32);
+void datblk(int32, int32);
+Sym* datsort(Sym*);
+void reloc(void);
+void relocsym(Sym*);
+void savedata(Sym*, Prog*);
+void symgrow(Sym*, int32);
+vlong addstring(Sym*, char*);
+vlong adduint32(Sym*, uint32);
+vlong adduint64(Sym*, uint64);
+vlong addaddr(Sym*, Sym*);
+vlong addaddrplus(Sym*, Sym*, int32);
+vlong addpcrelplus(Sym*, Sym*, int32);
+vlong addsize(Sym*, Sym*);
+vlong adduint8(Sym*, uint8);
+vlong adduint16(Sym*, uint16);
+void asmsym(void);
+void asmelfsym64(void);
+void strnput(char*, int);
+void dodata(void);
+void address(void);
+void textaddress(void);
+void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
+vlong datoff(vlong);
+void adddynlib(char*);
+int archreloc(Reloc*, Sym*, vlong*);
+void adddynsym(Sym*);
+void addexport(void);
int pathchar(void);
void* mal(uint32);
+void unmal(void*, uint32);
void mywhatsys(void);
+int rbyoff(const void*, const void*);
+
+uint16 le16(uchar*);
+uint32 le32(uchar*);
+uint64 le64(uchar*);
+uint16 be16(uchar*);
+uint32 be32(uchar*);
+uint64 be64(uchar*);
+
+typedef struct Endian Endian;
+struct Endian
+{
+ uint16 (*e16)(uchar*);
+ uint32 (*e32)(uchar*);
+ uint64 (*e64)(uchar*);
+};
+
+extern Endian be, le;
+
+// relocation size bits
+enum {
+ Rbig = 128,
+ Rlittle = 64,
+};
/* set by call to mywhatsys() */
extern char* goroot;
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 24400cf14..402e0ec63 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -6,6 +6,7 @@
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
#include "l.h"
+#include "../ld/dwarf.h"
#include "../ld/lib.h"
#include "../ld/macho.h"
@@ -46,6 +47,10 @@ newMachoLoad(uint32 type, uint32 ndata)
diag("too many loads");
errorexit();
}
+
+ if(macho64 && (ndata & 1))
+ ndata++;
+
l = &load[nload++];
l->type = type;
l->ndata = ndata;
@@ -97,22 +102,6 @@ newMachoDebug(void)
// Generic linking code.
-static uchar *linkdata;
-static uint32 nlinkdata;
-static uint32 mlinkdata;
-
-static uchar *strtab;
-static uint32 nstrtab;
-static uint32 mstrtab;
-
-struct Expsym
-{
- int off;
- Sym* s;
-} *expsym;
-static int nexpsym;
-static int nimpsym;
-
static char **dylib;
static int ndylib;
@@ -129,7 +118,7 @@ machowrite(void)
MachoDebug *d;
MachoLoad *l;
- o1 = Boffset(&bso);
+ o1 = cpos();
loadsize = 4*4*ndebug;
for(i=0; i<nload; i++)
@@ -194,8 +183,8 @@ machowrite(void)
LPUT(t->reloc);
LPUT(t->nreloc);
LPUT(t->flag);
- LPUT(0); /* reserved */
- LPUT(0); /* reserved */
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
LPUT(0); /* reserved */
} else {
strnput(t->name, 16);
@@ -207,8 +196,8 @@ machowrite(void)
LPUT(t->reloc);
LPUT(t->nreloc);
LPUT(t->flag);
- LPUT(0); /* reserved */
- LPUT(0); /* reserved */
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
}
}
}
@@ -229,224 +218,71 @@ machowrite(void)
LPUT(d->filesize);
}
- return Boffset(&bso) - o1;
-}
-
-static void*
-grow(uchar **dat, uint32 *ndat, uint32 *mdat, uint32 n)
-{
- uchar *p;
- uint32 old;
-
- if(*ndat+n > *mdat) {
- old = *mdat;
- *mdat = (*ndat+n)*2 + 128;
- *dat = realloc(*dat, *mdat);
- if(*dat == 0) {
- diag("out of memory");
- errorexit();
- }
- memset(*dat+old, 0, *mdat-old);
- }
- p = *dat + *ndat;
- *ndat += n;
- return p;
-}
-
-static int
-needlib(char *name)
-{
- char *p;
- Sym *s;
-
- /* reuse hash code in symbol table */
- p = smprint(".machoload.%s", name);
- s = lookup(p, 0);
- if(s->type == 0) {
- s->type = 100; // avoid SDATA, etc.
- return 1;
- }
- return 0;
+ return cpos() - o1;
}
void
domacho(void)
{
- int h, ptrsize, t;
- char *p;
- uchar *dat;
- uint32 x;
Sym *s;
- Sym **impsym;
- ptrsize = 4;
- if(macho64)
- ptrsize = 8;
+ if(debug['d'])
+ return;
// empirically, string table must begin with " \x00".
- if(!debug['d'])
- *(char*)grow(&strtab, &nstrtab, &mstrtab, 2) = ' ';
-
- impsym = nil;
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
- if(debug['d']) {
- diag("cannot use dynamic loading and -d");
- errorexit();
- }
- if(!s->dynexport) {
- if(nimpsym%32 == 0) {
- impsym = realloc(impsym, (nimpsym+32)*sizeof impsym[0]);
- if(impsym == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- impsym[nimpsym++] = s;
- continue;
- }
-
- /* symbol table entry - darwin still puts _ prefixes on all C symbols */
- x = nstrtab;
- p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1);
- *p++ = '_';
- strcpy(p, s->dynimpname);
-
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
-
- dat[4] = 0x0f; // type: N_SECT | N_EXT - external, defined in sect
- switch(s->type) {
- default:
- case STEXT:
- t = 1;
- break;
- case SDATA:
- t = 2;
- break;
- case SBSS:
- t = 4;
- break;
- }
- dat[5] = t; // sect: section number
-
- if (nexpsym%32 == 0) {
- expsym = realloc(expsym, (nexpsym+32)*sizeof expsym[0]);
- if (expsym == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- expsym[nexpsym].off = nlinkdata - ptrsize;
- expsym[nexpsym++].s = s;
- }
- }
-
- for(h=0; h<nimpsym; h++) {
- s = impsym[h];
- s->type = SMACHO;
- s->value = (nexpsym+h) * ptrsize;
-
- /* symbol table entry - darwin still puts _ prefixes on all C symbols */
- x = nstrtab;
- p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1);
- *p++ = '_';
- strcpy(p, s->dynimpname);
-
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
-
- dat[4] = 0x01; // type: N_EXT - external symbol
-
- if(needlib(s->dynimplib)) {
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- dylib[ndylib++] = s->dynimplib;
- }
- }
- free(impsym);
-
- /*
- * list of symbol table indexes.
- * we don't take advantage of the opportunity
- * to order the symbol table differently from
- * this list, so it is boring: 0 1 2 3 4 ...
- */
- for(x=0; x<nexpsym+nimpsym; x++) {
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 4);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
- }
-
- dynptrsize = (nexpsym+nimpsym) * ptrsize;
+ s = lookup(".dynstr", 0);
+ s->type = SMACHODYNSTR;
+ s->reachable = 1;
+ adduint8(s, ' ');
+ adduint8(s, '\0');
+
+ s = lookup(".dynsym", 0);
+ s->type = SMACHODYNSYM;
+ s->reachable = 1;
+
+ s = lookup(".plt", 0); // will be __symbol_stub
+ s->type = SMACHOPLT;
+ s->reachable = 1;
+
+ s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s->type = SMACHOGOT;
+ s->reachable = 1;
+
+ s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s->type = SMACHOINDIRECTPLT;
+ s->reachable = 1;
+
+ s = lookup(".linkedit.got", 0); // indirect table for .got
+ s->type = SMACHOINDIRECTGOT;
+ s->reachable = 1;
}
-vlong
-domacholink(void)
+void
+machoadddynlib(char *lib)
{
- int i;
- uchar *p;
- Sym *s;
- uint64 val;
-
- linkoff = 0;
- if(nlinkdata > 0) {
- linkoff = rnd(HEADR+textsize, INITRND) + rnd(datsize, INITRND);
- seek(cout, linkoff, 0);
-
- for(i = 0; i<nexpsym; ++i) {
- s = expsym[i].s;
- val = s->value;
- if(s->type == SUNDEF)
- diag("export of undefined symbol %s", s->name);
- if (s->type != STEXT)
- val += INITDAT;
- p = linkdata+expsym[i].off;
- p[0] = val;
- p[1] = val >> 8;
- p[2] = val >> 16;
- p[3] = val >> 24;
- if (macho64) {
- p[4] = val >> 32;
- p[5] = val >> 40;
- p[6] = val >> 48;
- p[7] = val >> 56;
- }
+ if(ndylib%32 == 0) {
+ dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
+ if(dylib == nil) {
+ diag("out of memory");
+ errorexit();
}
-
- write(cout, linkdata, nlinkdata);
- write(cout, strtab, nstrtab);
}
- return rnd(nlinkdata+nstrtab, INITRND);
+ dylib[ndylib++] = lib;
}
void
-asmbmacho(vlong symdatva, vlong symo)
+asmbmacho(void)
{
vlong v, w;
vlong va;
- int a, i, ptrsize;
+ int a, i;
char *pkgroot;
MachoHdr *mh;
MachoSect *msect;
MachoSeg *ms;
MachoDebug *md;
MachoLoad *ml;
+ Sym *s;
/* apple MACH */
va = INITTEXT - HEADR;
@@ -458,12 +294,10 @@ asmbmacho(vlong symdatva, vlong symo)
case '6':
mh->cpu = MACHO_CPU_AMD64;
mh->subcpu = MACHO_SUBCPU_X86;
- ptrsize = 8;
break;
case '8':
mh->cpu = MACHO_CPU_386;
mh->subcpu = MACHO_SUBCPU_X86;
- ptrsize = 4;
break;
}
@@ -472,8 +306,8 @@ asmbmacho(vlong symdatva, vlong symo)
ms->vsize = va;
/* text */
- v = rnd(HEADR+textsize, INITRND);
- ms = newMachoSeg("__TEXT", 1);
+ v = rnd(HEADR+segtext.len, INITRND);
+ ms = newMachoSeg("__TEXT", 2);
ms->vaddr = va;
ms->vsize = v;
ms->filesize = v;
@@ -482,45 +316,50 @@ asmbmacho(vlong symdatva, vlong symo)
msect = newMachoSect(ms, "__text");
msect->addr = INITTEXT;
- msect->size = textsize;
+ msect->size = segtext.sect->len;
msect->off = INITTEXT - va;
msect->flag = 0x400; /* flag - some instructions */
+
+ s = lookup(".plt", 0);
+ if(s->size > 0) {
+ msect = newMachoSect(ms, "__symbol_stub1");
+ msect->addr = symaddr(s);
+ msect->size = s->size;
+ msect->off = ms->fileoffset + msect->addr - ms->vaddr;
+ msect->flag = 0x80000408; /* flag */
+ msect->res1 = 0; /* index into indirect symbol table */
+ msect->res2 = 6; /* size of stubs */
+ }
/* data */
- w = datsize+dynptrsize+bsssize;
- ms = newMachoSeg("__DATA", 2+(dynptrsize>0));
+ w = segdata.len;
+ ms = newMachoSeg("__DATA", 3);
ms->vaddr = va+v;
ms->vsize = w;
ms->fileoffset = v;
- ms->filesize = datsize;
+ ms->filesize = segdata.filelen;
ms->prot1 = 7;
ms->prot2 = 3;
msect = newMachoSect(ms, "__data");
msect->addr = va+v;
- msect->size = datsize;
+ msect->size = symaddr(lookup(".got", 0)) - msect->addr;
msect->off = v;
- if(dynptrsize > 0) {
+ s = lookup(".got", 0);
+ if(s->size > 0) {
msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = va+v+datsize;
- msect->size = dynptrsize;
+ msect->addr = symaddr(s);
+ msect->size = s->size;
+ msect->off = datoff(msect->addr);
msect->align = 2;
msect->flag = 6; /* section with nonlazy symbol pointers */
- /*
- * The reserved1 field is supposed to be the index of
- * the first entry in the list of symbol table indexes
- * in isymtab for the symbols we need. We only use
- * pointers, so we need the entire list, so the index
- * here should be 0, which luckily is what the Mach-O
- * writing code emits by default for this not really reserved field.
- msect->reserved1 = 0; - first indirect symbol table entry we need
- */
+ msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
}
msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+datsize+dynptrsize;
- msect->size = bsssize;
+ msect->addr = va+v+segdata.filelen;
+ msect->size = segdata.len - segdata.filelen;
msect->flag = 1; /* flag - zero fill */
switch(thechar) {
@@ -532,7 +371,7 @@ asmbmacho(vlong symdatva, vlong symo)
ml->data[0] = 4; /* thread type */
ml->data[1] = 42; /* word count */
ml->data[2+32] = entryvalue(); /* start pc */
- ml->data[2+32+1] = entryvalue()>>32;
+ ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
break;
case '8':
ml = newMachoLoad(5, 16+2); /* unix thread */
@@ -543,39 +382,43 @@ asmbmacho(vlong symdatva, vlong symo)
}
if(!debug['d']) {
- int nsym;
+ Sym *s1, *s2, *s3, *s4;
- nsym = dynptrsize/ptrsize;
+ // must match domacholink below
+ s1 = lookup(".dynsym", 0);
+ s2 = lookup(".dynstr", 0);
+ s3 = lookup(".linkedit.plt", 0);
+ s4 = lookup(".linkedit.got", 0);
ms = newMachoSeg("__LINKEDIT", 0);
- ms->vaddr = va+v+rnd(datsize+dynptrsize+bsssize, INITRND);
- ms->vsize = nlinkdata+nstrtab;
+ ms->vaddr = va+v+rnd(segdata.len, INITRND);
+ ms->vsize = s1->size + s2->size + s3->size + s4->size;
ms->fileoffset = linkoff;
- ms->filesize = nlinkdata+nstrtab;
+ ms->filesize = ms->vsize;
ms->prot1 = 7;
ms->prot2 = 3;
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
- ml->data[1] = nsym; /* nsyms */
- ml->data[2] = linkoff + nlinkdata; /* stroff */
- ml->data[3] = nstrtab; /* strsize */
+ ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[2] = linkoff + s1->size; /* stroff */
+ ml->data[3] = s2->size; /* strsize */
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
ml->data[0] = 0; /* ilocalsym */
ml->data[1] = 0; /* nlocalsym */
ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = nexpsym; /* nextdefsym */
- ml->data[4] = nexpsym; /* iundefsym */
- ml->data[5] = nimpsym; /* nundefsym */
+ ml->data[3] = ndynexp; /* nextdefsym */
+ ml->data[4] = ndynexp; /* iundefsym */
+ ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
ml->data[6] = 0; /* tocoffset */
ml->data[7] = 0; /* ntoc */
ml->data[8] = 0; /* modtaboff */
ml->data[9] = 0; /* nmodtab */
ml->data[10] = 0; /* extrefsymoff */
ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + nlinkdata - nsym*4; /* indirectsymoff */
- ml->data[13] = nsym; /* nindirectsyms */
+ ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */
+ ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */
ml->data[14] = 0; /* extreloff */
ml->data[15] = 0; /* nextrel */
ml->data[16] = 0; /* locreloff */
@@ -602,24 +445,53 @@ asmbmacho(vlong symdatva, vlong symo)
}
if(!debug['s']) {
- ms = newMachoSeg("__SYMDAT", 1);
- ms->vaddr = symdatva;
- ms->vsize = 8+symsize+lcsize;
- ms->fileoffset = symo;
- ms->filesize = 8+symsize+lcsize;
- ms->prot1 = 7;
- ms->prot2 = 5;
+ Sym *s;
md = newMachoDebug();
- md->fileoffset = symo+8;
- md->filesize = symsize;
+ s = lookup("symtab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
md = newMachoDebug();
- md->fileoffset = symo+8+symsize;
- md->filesize = lcsize;
+ s = lookup("pclntab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
+
+ dwarfaddmachoheaders();
}
a = machowrite();
if(a > MACHORESERVE)
diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
}
+
+vlong
+domacholink(void)
+{
+ int size;
+ Sym *s1, *s2, *s3, *s4;
+
+ // write data that will be linkedit section
+ s1 = lookup(".dynsym", 0);
+ relocsym(s1);
+ s2 = lookup(".dynstr", 0);
+ s3 = lookup(".linkedit.plt", 0);
+ s4 = lookup(".linkedit.got", 0);
+
+ while(s2->size%4)
+ adduint8(s2, 0);
+
+ size = s1->size + s2->size + s3->size + s4->size;
+
+ if(size > 0) {
+ linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ seek(cout, linkoff, 0);
+
+ ewrite(cout, s1->p, s1->size);
+ ewrite(cout, s2->p, s2->size);
+ ewrite(cout, s3->p, s3->size);
+ ewrite(cout, s4->p, s4->size);
+ }
+
+ return rnd(size, INITRND);
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index a96b2a383..4cc7edc80 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -18,6 +18,8 @@ struct MachoSect {
uint32 reloc;
uint32 nreloc;
uint32 flag;
+ uint32 res1;
+ uint32 res2;
};
typedef struct MachoSeg MachoSeg;
@@ -70,8 +72,23 @@ enum {
MACHO32SYMSIZE = 12,
MACHO64SYMSIZE = 16,
+
+ MACHO_X86_64_RELOC_UNSIGNED = 0,
+ MACHO_X86_64_RELOC_SIGNED = 1,
+ MACHO_X86_64_RELOC_BRANCH = 2,
+ MACHO_X86_64_RELOC_GOT_LOAD = 3,
+ MACHO_X86_64_RELOC_GOT = 4,
+ MACHO_X86_64_RELOC_SUBTRACTOR = 5,
+ MACHO_X86_64_RELOC_SIGNED_1 = 6,
+ MACHO_X86_64_RELOC_SIGNED_2 = 7,
+ MACHO_X86_64_RELOC_SIGNED_4 = 8,
+
+ MACHO_GENERIC_RELOC_VANILLA = 0,
+
+ MACHO_FAKE_GOTPCREL = 100,
};
void domacho(void);
vlong domacholink(void);
-void asmbmacho(vlong, vlong);
+void asmbmacho(void);
+void machoadddynlib(char*);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index d3439abfb..82c6941f2 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -33,18 +33,39 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+int32 PESECTHEADR;
+int32 PEFILEHEADR;
+
static int pe64;
static int nsect;
-static int sect_virt_begin;
-static int sect_raw_begin = PERESERVE;
+static int nextsectoff;
+static int nextfileoff;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
static IMAGE_SECTION_HEADER sh[16];
-static IMAGE_SECTION_HEADER *textsect, *datsect, *bsssect;
+
+typedef struct Imp Imp;
+struct Imp {
+ Sym* s;
+ long va;
+ long vb;
+ Imp* next;
+};
+
+typedef struct Dll Dll;
+struct Dll {
+ char* name;
+ int count;
+ Imp* ms;
+ Dll* next;
+};
+
+static Dll* dr;
+static int ndll, nimp, nsize;
static IMAGE_SECTION_HEADER*
-new_section(char *name, int size, int noraw)
+addpesection(char *name, int sectsize, int filesize, Segment *s)
{
IMAGE_SECTION_HEADER *h;
@@ -54,15 +75,23 @@ new_section(char *name, int size, int noraw)
}
h = &sh[nsect++];
strncpy((char*)h->Name, name, sizeof(h->Name));
- h->VirtualSize = size;
- if(!sect_virt_begin)
- sect_virt_begin = 0x1000;
- h->VirtualAddress = sect_virt_begin;
- sect_virt_begin = rnd(sect_virt_begin+size, 0x1000);
- if(!noraw) {
- h->SizeOfRawData = rnd(size, PEALIGN);
- h->PointerToRawData = sect_raw_begin;
- sect_raw_begin += h->SizeOfRawData;
+ h->VirtualSize = sectsize;
+ h->VirtualAddress = nextsectoff;
+ nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
+ h->PointerToRawData = nextfileoff;
+ if(filesize > 0) {
+ h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
+ nextfileoff += h->SizeOfRawData;
+ }
+ if(s) {
+ if(s->vaddr-PEBASE != h->VirtualAddress) {
+ diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
+ errorexit();
+ }
+ if(s->fileoff != h->PointerToRawData) {
+ diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
+ errorexit();
+ }
}
return h;
}
@@ -79,6 +108,11 @@ peinit(void)
default:
break;
}
+
+ PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN);
+ PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
+ nextsectoff = PESECTHEADR;
+ nextfileoff = PEFILEHEADR;
}
static void
@@ -86,7 +120,8 @@ pewrite(void)
{
int i, j;
- write(cout, dosstub, sizeof dosstub);
+ seek(cout, 0, 0);
+ ewrite(cout, dosstub, sizeof dosstub);
strnput("PE", 4);
for (i=0; i<sizeof(fh); i++)
@@ -98,24 +133,6 @@ pewrite(void)
cput(((char*)&sh[i])[j]);
}
-void
-dope(void)
-{
- textsect = new_section(".text", textsize, 0);
- textsect->Characteristics = IMAGE_SCN_CNT_CODE|
- IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
-
- datsect = new_section(".data", datsize, 0);
- datsect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- INITDAT = PEBASE+datsect->VirtualAddress;
-
- bsssect = new_section(".bss", bsssize, 1);
- bsssect->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-}
-
static void
strput(char *s)
{
@@ -124,73 +141,167 @@ strput(char *s)
cput('\0');
}
-static void
-add_import_table(void)
+static Dll*
+initdynimport(void)
{
- IMAGE_IMPORT_DESCRIPTOR ds[2], *d;
- char *dllname = "kernel32.dll";
- struct {
- char *name;
- uint32 thunk;
- } *f, fs[] = {
- { "GetProcAddress", 0 },
- { "LoadLibraryExA", 0 },
- { 0, 0 }
- };
-
- uint32 size = 0;
- memset(ds, 0, sizeof(ds));
- size += sizeof(ds);
- ds[0].Name = size;
- size += strlen(dllname) + 1;
- for(f=fs; f->name; f++) {
- f->thunk = size;
- size += sizeof(uint16) + strlen(f->name) + 1;
+ Imp *m;
+ Dll *d;
+ Sym *s;
+ 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)
+ 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;
+ }
+ }
+
+ nsize += 20*ndll + 20;
+ nsize += 4*nimp + 4*ndll;
+
+ dynamic = lookup(".windynamic", 0);
+ dynamic->reachable = 1;
+ dynamic->type = SWINDOWS;
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ m->s->type = SWINDOWS | SSUB;
+ m->s->sub = dynamic->sub;
+ dynamic->sub = m->s;
+ m->s->value = dynamic->size;
+ dynamic->size += 4;
+ }
+ dynamic->size += 4;
}
- ds[0].FirstThunk = size;
- for(f=fs; f->name; f++)
- size += sizeof(fs[0].thunk);
+
+ return dr;
+}
+static void
+addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
+{
IMAGE_SECTION_HEADER *isect;
- isect = new_section(".idata", size, 0);
+ uint32 va;
+ int noff, aoff, o, last_fn, last_name_off, iat_off;
+ Imp *m;
+ Dll *d;
+ Sym* dynamic;
+
+ isect = addpesection(".idata", nsize, nsize, 0);
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-
- uint32 va = isect->VirtualAddress;
+ va = isect->VirtualAddress;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
- ds[0].Name += va;
- ds[0].FirstThunk += va;
- for(f=fs; f->name; f++)
- f->thunk += va;
+ seek(cout, fileoff, 0);
- vlong off = seek(cout, 0, 1);
- seek(cout, 0, 2);
- for(d=ds; ; d++) {
- lputl(d->OriginalFirstThunk);
- lputl(d->TimeDateStamp);
- lputl(d->ForwarderChain);
- lputl(d->Name);
- lputl(d->FirstThunk);
- if(!d->Name)
- break;
+ 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(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;
}
- strput(dllname);
- for(f=fs; f->name; f++) {
- wputl(0);
- strput(f->name);
+ lputl(0); //end
+ lputl(0);
+ lputl(0);
+ lputl(0);
+ lputl(0);
+
+ // 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);
+ }
+ }
+
+ strnput("", isect->SizeOfRawData - nsize);
+ cflush();
+
+ // 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);
}
- for(f=fs; f->name; f++)
- lputl(f->thunk);
- strnput("", isect->SizeOfRawData - size);
cflush();
- seek(cout, off, 0);
+ seek(cout, 0, 2);
+}
+
+void
+dope(void)
+{
+ initdynimport();
}
void
asmbpe(void)
{
+ IMAGE_SECTION_HEADER *t, *d;
+
switch(thechar) {
default:
diag("unknown PE architecture");
@@ -203,14 +314,16 @@ asmbpe(void)
break;
}
- if(!debug['s']) {
- IMAGE_SECTION_HEADER *symsect;
- symsect = new_section(".symdat", 8+symsize+lcsize, 0);
- symsect->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_CNT_INITIALIZED_DATA;
- }
+ t = addpesection(".text", segtext.len, segtext.len, &segtext);
+ t->Characteristics = IMAGE_SCN_CNT_CODE|
+ IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
+
+ d = addpesection(".data", segdata.len, segdata.filelen, &segdata);
+ d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- add_import_table();
+ addimports(nextfileoff, d);
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
@@ -223,24 +336,24 @@ asmbpe(void)
oh.Magic = 0x10b; // PE32
oh.MajorLinkerVersion = 1;
oh.MinorLinkerVersion = 0;
- oh.SizeOfCode = textsect->SizeOfRawData;
- oh.SizeOfInitializedData = datsect->SizeOfRawData;
- oh.SizeOfUninitializedData = bsssect->SizeOfRawData;
+ oh.SizeOfCode = t->SizeOfRawData;
+ oh.SizeOfInitializedData = d->SizeOfRawData;
+ oh.SizeOfUninitializedData = 0;
oh.AddressOfEntryPoint = entryvalue()-PEBASE;
- oh.BaseOfCode = textsect->VirtualAddress;
- oh.BaseOfData = datsect->VirtualAddress;
+ oh.BaseOfCode = t->VirtualAddress;
+ oh.BaseOfData = d->VirtualAddress;
oh.ImageBase = PEBASE;
- oh.SectionAlignment = 0x00001000;
- oh.FileAlignment = PEALIGN;
+ 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 = sect_virt_begin;
- oh.SizeOfHeaders = PERESERVE;
+ oh.SizeOfImage = nextsectoff;
+ oh.SizeOfHeaders = PEFILEHEADR;
oh.Subsystem = 3; // WINDOWS_CUI
oh.SizeOfStackReserve = 0x00200000;
oh.SizeOfStackCommit = 0x00001000;
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index b64dd97c0..f8161cc4a 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -72,9 +72,16 @@ typedef struct {
uint32 FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
-#define PERESERVE 0x400
-#define PEALIGN 0x200
#define PEBASE 0x00400000
+// SectionAlignment must be greater than or equal to FileAlignment.
+// The default is the page size for the architecture.
+#define PESECTALIGN 0x1000
+// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
+// The default is 512. If the SectionAlignment is less than
+// the architecture's page size, then FileAlignment must match SectionAlignment.
+#define PEFILEALIGN (2<<8)
+extern int32 PESECTHEADR;
+extern int32 PEFILEHEADR;
enum {
IMAGE_FILE_MACHINE_I386 = 0x14c,
@@ -112,5 +119,6 @@ enum {
};
void peinit(void);
-void dope(void);
void asmbpe(void);
+void dope(void);
+
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
new file mode 100644
index 000000000..26e4def64
--- /dev/null
+++ b/src/cmd/ld/symtab.c
@@ -0,0 +1,259 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.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.
+
+// Symbol table.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+
+char *elfstrdat;
+int elfstrsize;
+int maxelfstr;
+int elftextsh;
+
+int
+putelfstr(char *s)
+{
+ int off, n;
+
+ if(elfstrsize == 0 && s[0] != 0) {
+ // first entry must be empty string
+ putelfstr("");
+ }
+
+ n = strlen(s)+1;
+ if(elfstrsize+n > maxelfstr) {
+ maxelfstr = 2*(elfstrsize+n+(1<<20));
+ elfstrdat = realloc(elfstrdat, maxelfstr);
+ }
+ off = elfstrsize;
+ elfstrsize += n;
+ memmove(elfstrdat+off, s, n);
+ return off;
+}
+
+void
+putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int bind, type, shndx, stroff;
+
+ bind = STB_GLOBAL;
+ switch(t) {
+ default:
+ return;
+ case 'T':
+ type = STT_FUNC;
+ shndx = elftextsh + 0;
+ break;
+ case 'D':
+ type = STT_OBJECT;
+ shndx = elftextsh + 1;
+ break;
+ case 'B':
+ type = STT_OBJECT;
+ shndx = elftextsh + 2;
+ break;
+ }
+
+ stroff = putelfstr(s);
+ LPUT(stroff); // string
+ cput((bind<<4)|(type&0xF));
+ cput(0);
+ WPUT(shndx);
+ VPUT(addr);
+ VPUT(size);
+}
+
+void
+asmelfsym64(void)
+{
+ genasmsym(putelfsym64);
+}
+
+void
+putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int bind, type, shndx, stroff;
+
+ bind = STB_GLOBAL;
+ switch(t) {
+ default:
+ return;
+ case 'T':
+ type = STT_FUNC;
+ shndx = elftextsh + 0;
+ break;
+ case 'D':
+ type = STT_OBJECT;
+ shndx = elftextsh + 1;
+ break;
+ case 'B':
+ type = STT_OBJECT;
+ shndx = elftextsh + 2;
+ break;
+ }
+
+ stroff = putelfstr(s);
+ LPUT(stroff); // string
+ LPUT(addr);
+ LPUT(size);
+ cput((bind<<4)|(type&0xF));
+ cput(0);
+ WPUT(shndx);
+}
+
+void
+asmelfsym32(void)
+{
+ genasmsym(putelfsym32);
+}
+
+
+static Sym *symt;
+
+static void
+scput(int b)
+{
+ uchar *p;
+
+ symgrow(symt, symt->size+1);
+ p = symt->p + symt->size;
+ *p = b;
+ symt->size++;
+}
+
+static void
+slputb(int32 v)
+{
+ uchar *p;
+
+ symgrow(symt, symt->size+4);
+ p = symt->p + symt->size;
+ *p++ = v>>24;
+ *p++ = v>>16;
+ *p++ = v>>8;
+ *p = v;
+ symt->size += 4;
+}
+
+void
+putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
+{
+ int i, f, l;
+ Reloc *rel;
+
+ if(t == 'f')
+ name++;
+ l = 4;
+// if(!debug['8'])
+// l = 8;
+ if(s != nil) {
+ rel = addrel(symt);
+ rel->siz = l + Rbig;
+ rel->sym = s;
+ rel->type = D_ADDR;
+ rel->off = symt->size;
+ v = 0;
+ }
+ if(l == 8)
+ slputb(v>>32);
+ slputb(v);
+ if(ver)
+ t += 'a' - 'A';
+ scput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ scput(name[0]);
+ for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) {
+ scput(name[i]);
+ scput(name[i+1]);
+ }
+ scput(0);
+ scput(0);
+ i++;
+ }
+ else {
+ for(i=0; name[i]; i++)
+ scput(name[i]);
+ scput(0);
+ }
+ if(typ) {
+ if(!typ->reachable)
+ diag("unreachable type %s", typ->name);
+ rel = addrel(symt);
+ rel->siz = l;
+ rel->sym = typ;
+ rel->type = D_ADDR;
+ rel->off = symt->size;
+ }
+ if(l == 8)
+ slputb(0);
+ slputb(0);
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8llux ", t, v);
+ for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) {
+ f = ((name[i]&0xff) << 8) | (name[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s, ver, typ ? typ->name : "");
+ else
+ Bprint(&bso, "%c %.8llux %s %s\n", t, v, s, typ ? typ->name : "");
+ }
+}
+
+void
+symtab(void)
+{
+ // Define these so that they'll get put into the symbol table.
+ // data.c:/^address will provide the actual values.
+ xdefine("text", STEXT, 0);
+ xdefine("etext", STEXT, 0);
+ xdefine("rodata", SRODATA, 0);
+ xdefine("erodata", SRODATA, 0);
+ xdefine("data", SBSS, 0);
+ xdefine("edata", SBSS, 0);
+ xdefine("end", SBSS, 0);
+ xdefine("epclntab", SRODATA, 0);
+ xdefine("esymtab", SRODATA, 0);
+
+ symt = lookup("symtab", 0);
+ symt->type = SRODATA;
+ symt->size = 0;
+ symt->reachable = 1;
+
+ genasmsym(putsymb);
+}
diff --git a/src/cmd/make.bash b/src/cmd/make.bash
index d0fda7d18..63da74625 100755
--- a/src/cmd/make.bash
+++ b/src/cmd/make.bash
@@ -7,9 +7,7 @@ set -e
bash clean.bash
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../Make.inc go-env)
if [ -z "$O" ]; then
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
exit 1
@@ -17,16 +15,16 @@ fi
cd ${O}l
bash mkenam
-"$GOBIN"/gomake enam.o
+gomake enam.o
cd ..
# Note: commands written in Go are not listed here.
-# They are in ../make.bash so that they can be built
+# They are in ../pkg/Makefile so that they can be built
# after the Go libraries on which they depend.
for i in cc ${O}l ${O}a ${O}c gc ${O}g cov godefs gopack gotest nm prof
do
echo; echo; echo %%%% making $i %%%%; echo
cd $i
- "$GOBIN"/gomake install
+ gomake install
cd ..
done
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
index bb1545122..383dbd973 100644
--- a/src/cmd/nm/Makefile
+++ b/src/cmd/nm/Makefile
@@ -2,23 +2,17 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
# The directory is nm because the source is portable and general.
-# We call the binary 6nm to avoid confusion and because this binary
-# is linked only with amd64 and x86 support.
+# We call the binary 6nm to avoid confusion with the host nm.
TARG=6nm
OFILES=\
nm.$O\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
index 978218bff..845b6c773 100644
--- a/src/cmd/nm/nm.c
+++ b/src/cmd/nm/nm.c
@@ -126,31 +126,34 @@ void
doar(Biobuf *bp)
{
int offset, size, obj;
- char membername[SARNAME];
+ char name[SARNAME];
multifile = 1;
for (offset = Boffset(bp);;offset += size) {
- size = nextar(bp, offset, membername);
+ size = nextar(bp, offset, name);
if (size < 0) {
- error("phase error on ar header %ld", offset);
+ error("phase error on ar header %d", offset);
return;
}
if (size == 0)
return;
- if (strcmp(membername, symname) == 0)
+ if (strcmp(name, symname) == 0)
continue;
obj = objtype(bp, 0);
if (obj < 0) {
+ // perhaps foreign object
+ if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
+ return;
error("inconsistent file %s in %s",
- membername, filename);
+ name, filename);
return;
}
if (!readar(bp, obj, offset+size, 1)) {
error("invalid symbol reference in file %s",
- membername);
+ name);
return;
}
- filename = membername;
+ filename = name;
nsym=0;
objtraverse(psym, 0);
printsyms(symptr, nsym);
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
index 602c07da6..e643f267c 100644
--- a/src/cmd/prof/Makefile
+++ b/src/cmd/prof/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
# The directory is prof because the source is portable and general.
# We call the binary 6prof to avoid confusion and because this binary
@@ -12,19 +13,22 @@ TARG=6prof
OFILES=\
main.$O\
-#HFILES=\
-# defs.h\
-# fns.h\
+LIB=\
+ ../../../lib/libmach.a\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+NOINSTALL=1
+include ../../Make.ccmd
-clean:
- rm -f *.$O $(TARG)
+ifeq ($(GOOS),windows)
+NAME=windows
+else
+NAME=$(shell uname | tr A-Z a-z)
+endif
-install: install-$(shell uname | tr A-Z a-z) install-pprof
+install: install-$(NAME) install-pprof
install-linux: install-default
install-freebsd: install-default
+install-windows: install-default
# on Darwin, have to install and setgid; see $GOROOT/src/sudo.bash
install-darwin: $(TARG)
@@ -33,7 +37,5 @@ install-darwin: $(TARG)
install-default: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG)
-$(OFILES): $(HFILES)
-
install-pprof: gopprof
cp gopprof "$(GOBIN)"/gopprof
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
index dffeeffa1..4bcfa5800 100755
--- a/src/cmd/prof/gopprof
+++ b/src/cmd/prof/gopprof
@@ -2736,6 +2736,7 @@ sub IsSymbolizedProfileFile {
sub CheckSymbolPage {
my $url = SymbolPageURL();
+print STDERR "Read $url\n";
open(SYMBOL, "$CURL -s '$url' |");
my $line = <SYMBOL>;
$line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
@@ -2816,7 +2817,7 @@ sub ResolveRedirectionForCurl {
# $main::prog to have the correct program name.
sub ReadSymbols {
my $in = shift;
- my $map = {};
+ my $map = shift;
while (<$in>) {
s/\r//g; # turn windows-looking lines into unix-looking lines
# Removes all the leading zeroes from the symbols, see comment below.
@@ -2858,20 +2859,30 @@ sub FetchSymbols {
my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
if (!defined($symbol_map)) {
- my $post_data = join("+", sort((map {"0x" . "$_"} @pcs)));
-
- open(POSTFILE, ">$main::tmpfile_sym");
- print POSTFILE $post_data;
- close(POSTFILE);
-
- my $url = SymbolPageURL();
- $url = ResolveRedirectionForCurl($url);
- my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
- # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
- my $cppfilt = $obj_tool_map{"c++filt"};
- open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
- $symbol_map = ReadSymbols(*SYMBOL{IO});
- close(SYMBOL);
+ $symbol_map = {};
+ my @toask = @pcs;
+ while (@toask > 0) {
+ my $n = @toask;
+ if ($n > 49) { $n = 49; }
+ my @thisround = @toask[0..$n];
+my $t = @toask;
+print STDERR "$n $t\n";
+ @toask = @toask[($n+1)..(@toask-1)];
+ my $post_data = join("+", sort((map {"0x" . "$_"} @thisround)));
+ open(POSTFILE, ">$main::tmpfile_sym");
+ print POSTFILE $post_data;
+ close(POSTFILE);
+
+print STDERR "SYMBL!\n";
+ my $url = SymbolPageURL();
+ $url = ResolveRedirectionForCurl($url);
+ my $command_line = "$CURL -sd '\@$main::tmpfile_sym' '$url'";
+ # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
+ my $cppfilt = $obj_tool_map{"c++filt"};
+ open(SYMBOL, "$command_line | $cppfilt |") or error($command_line);
+ ReadSymbols(*SYMBOL{IO}, $symbol_map);
+ close(SYMBOL);
+ }
}
my $symbols = {};
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
index 2bb67f596..f36759cd3 100644
--- a/src/cmd/prof/main.c
+++ b/src/cmd/prof/main.c
@@ -53,9 +53,10 @@ Map *map[32]; // thread maps
void
Usage(void)
{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]\n");
+ fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec]\n");
+ fprint(2, " prof [-t total_secs] [-d delta_msec] 6.out args ...\n");
fprint(2, "\tformats (default -h):\n");
- fprint(2, "\t\t-c file.prof: write [c]pprof output to file.prof\n");
+ fprint(2, "\t\t-P file.prof: write [c]pprof output to file.prof\n");
fprint(2, "\t\t-h: histograms\n");
fprint(2, "\t\t-f: dynamic functions\n");
fprint(2, "\t\t-l: dynamic file and line numbers\n");
@@ -192,22 +193,22 @@ amd64_ppword(uvlong w)
void
x86_regprint(void)
{
- fprint(2, "ax\t0x%llux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%llux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%llux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%llux\n", ureg_x86.dx);
- fprint(2, "si\t0x%llux\n", ureg_x86.si);
- fprint(2, "di\t0x%llux\n", ureg_x86.di);
- fprint(2, "bp\t0x%llux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%llux\n", ureg_x86.ds);
- fprint(2, "es\t0x%llux\n", ureg_x86.es);
- fprint(2, "fs\t0x%llux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%llux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%llux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%llux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%llux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%llux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%llux\n", ureg_x86.ss);
+ fprint(2, "ax\t0x%ux\n", ureg_x86.ax);
+ fprint(2, "bx\t0x%ux\n", ureg_x86.bx);
+ fprint(2, "cx\t0x%ux\n", ureg_x86.cx);
+ fprint(2, "dx\t0x%ux\n", ureg_x86.dx);
+ fprint(2, "si\t0x%ux\n", ureg_x86.si);
+ fprint(2, "di\t0x%ux\n", ureg_x86.di);
+ fprint(2, "bp\t0x%ux\n", ureg_x86.bp);
+ fprint(2, "ds\t0x%ux\n", ureg_x86.ds);
+ fprint(2, "es\t0x%ux\n", ureg_x86.es);
+ fprint(2, "fs\t0x%ux\n", ureg_x86.fs);
+ fprint(2, "gs\t0x%ux\n", ureg_x86.gs);
+ fprint(2, "cs\t0x%ux\n", ureg_x86.cs);
+ fprint(2, "flags\t0x%ux\n", ureg_x86.flags);
+ fprint(2, "pc\t0x%ux\n", ureg_x86.pc);
+ fprint(2, "sp\t0x%ux\n", ureg_x86.sp);
+ fprint(2, "ss\t0x%ux\n", ureg_x86.ss);
}
int